自增操作的原子性

Atomicity of increment operation

我正在学习 'Java Concurrency in Practice' 的多线程编程。

书中曾说过,即使是看似无害的增量操作也不是线程安全的,因为它由三种不同的操作组成...读取、修改和写入。

class A {
  private void int c;

  public void increment() {
    ++c;
  }
}

所以增量语句不是原子的,因此不是线程安全的。

我的问题是,如果一个环境真的是并发的(即多个线程能够完全同时执行它们的程序语句)那么一个真正原子的语句也不能是线程安全的,因为多个线程可以读取相同的值。 那么拥有原子语句如何有助于在并发环境中实现线程安全?

真正的并发在修改状态时是不存在的。

This post 对并发和并行有一些很好的描述。

正如@RitchieHindle 所说 post:

Concurrency is when two tasks can start, run, and complete in overlapping time periods. It doesn't necessarily mean they'll ever both be running at the same instant. Eg. multitasking on a single-core machine.

举个例子,非原子操作的危险在于一个线程可能读取值,另一个线程可能修改值,然后原始线程可能修改并写入值(从而否定第二个线程的修改做过)。

原子操作不允许其他操作在原子操作中间访问状态。例如,如果增量运算符是原子的,那么在这些操作发生时,它会读取、修改和写入,而无需任何其他线程访问该变量状态。

您可以使用 AtomicInteger. The linked Javadoc says (in part) that it is an int value that may be updated atomically. AtomicInteger also implements addAndGet(int),它 自动将给定值添加到当前值

private AtomicInteger ai = new AtomicInteger(1); // <-- or another initial value
public int increment() {
    return ai.addAndGet(1); // <-- or another increment value
}

这可以(例如)允许您保证多个线程的写入顺序一致性。考虑一下,ai 可能代表(或包含)某些 static(或全局)资源。如果一个值是线程局部的,那么你不需要考虑原子性。