这是一个独立的示例可执行应用程序,它证明了仅靠 volatile 是不够的。四个线程每个都将计数器递增 10,000 次,因此您希望计数器最终为 40,000。它使用一个原始 int 变量和一个 AtomicInt,并且每次尝试练习 5 次。
import java.util.Collections;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
class AtomicDemo {
interface Demo extends Callable<Void> {
int getCounter();
}
static class UsePrimitive implements Demo {
private volatile int counter = 0;
public Void call() throws Exception {
for (int i = 1; i <= 10000; ++i) {
++counter;
}
return null;
}
public int getCounter() {
return counter;
}
}
static class UseAtomic implements Demo {
final AtomicInteger counter = new AtomicInteger(0);
public Void call() throws Exception {
for (int i = 1; i <= 10000; ++i) {
counter.incrementAndGet();
System.out.print("");
}
return null;
}
public int getCounter() {
return counter.get();
}
}
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newFixedThreadPool(4);
for (int i = 1; i <= 5; ++i) {
Demo demo = new UsePrimitive();
exec.invokeAll(Collections.nCopies(4, demo));
System.out.println("Count to 40000 using primitive, attempt number " + i + ": " + demo.getCounter());
}
for (int i = 1; i <= 5; ++i) {
Demo demo = new UseAtomic();
exec.invokeAll(Collections.nCopies(4, demo));
System.out.println("Count to 40000 using atomic, attempt number " + i + ": " + demo.getCounter());
}
exec.shutdownNow();
}
}
典型输出:
Count to 40000 using primitive, attempt number 1: 39711
Count to 40000 using primitive, attempt number 2: 39686
Count to 40000 using primitive, attempt number 3: 39972
Count to 40000 using primitive, attempt number 4: 39840
Count to 40000 using primitive, attempt number 5: 39865
Count to 40000 using atomic, attempt number 1: 40000
Count to 40000 using atomic, attempt number 2: 40000
Count to 40000 using atomic, attempt number 3: 40000
Count to 40000 using atomic, attempt number 4: 40000
Count to 40000 using atomic, attempt number 5: 40000
您看,只有使用 AtomicInt 才能始终获得预期的结果。