在不直接使用同步的情况下避免Java中的丢失更新

nas*_*ash 4 java synchronization

我想知道是否有可能避免丢失更新问题,其中多个线程正在更新相同的日期,同时避免使用synchronized(x) { }.

我会做很多添加和增量:

val++;
ary[x] += y;
ary[z]++;
Run Code Online (Sandbox Code Playgroud)

我不知道Java如何将这些编译成字节代码,如果一个线程可以在其中一个语句块的字节代码中间被中断.换句话说那些语句线程安全吗?

另外,我知道Vector类是同步的,但我不确定这意味着什么.以下代码是否是线程安全的,因为位置上的值i不会在vec.get(i)和之间发生变化vec.set(...).

class myClass {
  Vector<Integer> vec = new Vector<>(Integer);

  public void someMethod() {
    for (int i=0; i < vec.size(); i++)
      vec.set(i, vec.get(i) + value);
  }
}
Run Code Online (Sandbox Code Playgroud)

提前致谢.

Tom*_*ine 6

对于线程的目的,++并且+=被视为两个操作(四为doublelong).所以更新可以互相破坏.不只是一个,但是在错误的时刻采取行动的调度程序可能会消除毫秒的更新.

java.util.concurrent.atomic 是你的朋友.

您的代码可以安全,假设您不介意每个元素单独更新,并且您不更改大小(!),如下所示:

for (int i=0; i < vec.size(); i++) {
    synchronized (vec) {
        vec.set(i, vec.get(i) + value);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你想要调整大小,Vector你需要将synchronized语句移到for循环之外,你也可以只使用普通的new ArrayList.实际上并没有大量使用同步列表.

但你可以使用AtomicIntegerArray:

private final AtomicIntegerArray ints = new AtomicIntegerArray(KNOWN_SIZE);
[...]
    int len = ints.length();
    for (int i=0; i<len; ++i) {
        ints.addAndGet(i, value);
    }
}
Run Code Online (Sandbox Code Playgroud)

这有没有锁(!)和没有拳击的优势.实现也很有趣,你需要了解它做更复杂的更新(例如随机数生成器).