我同意@Kumar的答案。
易失性是不够的 - 它对内存顺序有一些影响,但不能确保++的原子性。
关于多线程编程的真正困难之处在于,问题可能不会出现在任何合理的测试量中。我写了一个程序来演示这个问题,但它的线程除了递增计数器之外什么都不做。即便如此,计数仍在正确答案的1%以内。在线程有其他工作要做的实际程序中,两个线程执行 ++ 的可能性可能非常低,足以同时显示问题。多线程的正确性不能被测试,它必须被设计进去。
该程序使用简单的静态int,易失性int和AtomicInteger执行相同的计数任务。只有 AtomicInteger 才能始终如一地获得正确的答案。具有 4 个双线程内核的多处理器上的典型输出为:
count: 1981788 volatileCount: 1982139 atomicCount: 2000000 Expected count: 2000000
下面是源代码:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class Test {
private static int COUNTS_PER_THREAD = 1000000;
private static int THREADS = 2;
private static int count = 0;
private static volatile int volatileCount = 0;
private static AtomicInteger atomicCount = new AtomicInteger();
public static void main(String[] args) throws InterruptedException {
List<Thread> threads = new ArrayList<Thread>(THREADS);
for (int i = 0; i < THREADS; i++) {
threads.add(new Thread(new Counter()));
}
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
t.join();
}
System.out.println("count: " + count + " volatileCount: " + volatileCount + " atomicCount: "
+ atomicCount + " Expected count: "
+ (THREADS * COUNTS_PER_THREAD));
}
private static class Counter implements Runnable {
@Override
public void run() {
for (int i = 0; i < COUNTS_PER_THREAD; i++) {
count++;
volatileCount++;
atomicCount.incrementAndGet();
}
}
}
}