Demo类com.oldratlee.fucking.concurrency.WrongCounterDemo
。
Demo说明
主线程中开启2个任务线程执行并发递增计数。主线程最终结果检查。
问题说明
计数值不对。
快速运行
mvn compile exec:java -Dexec.mainClass=com.oldratlee.fucking.concurrency.WrongCounterDemo
下面的demo即使有volatile属性也是不能保证计数器的正确性的。
public class WrongCounterDemo {
private static final int INC_COUNT = 100000000;
volatile int counter = 0;
public static void main(String[] args) throws Exception {
WrongCounterDemo demo = new WrongCounterDemo();
System.out.println("Start task thread!");
Thread thread1 = new Thread(demo.getConcurrencyCheckTask());
thread1.start();
Thread thread2 = new Thread(demo.getConcurrencyCheckTask());
thread2.start();
thread1.join();
thread2.join();
int actualCounter = demo.counter;
int expectedCount = INC_COUNT * 2;
if (actualCounter != expectedCount) {
// 在我的开发机上,几乎必现!即使counter上加了volatile。(简单安全的解法:使用AtomicInteger)
System.err.printf("Fuck! Got wrong count!! actual %s, expected: %s.", actualCounter, expectedCount);
} else {
System.out.println("Wow... Got right count!");
}
}
ConcurrencyCheckTask getConcurrencyCheckTask() {
return new ConcurrencyCheckTask();
}
private class ConcurrencyCheckTask implements Runnable {
@Override
public void run() {
for (int i = 0; i < INC_COUNT; ++i) {
++counter;
}
}
}
}
接下来使用AtomicInteger做计数器,就可以不用volatile变量了。
public class WrongCounterDemo {
private static final int INC_COUNT = 100000000;
AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) throws Exception {
WrongCounterDemo demo = new WrongCounterDemo();
System.out.println("Start task thread!");
Thread thread1 = new Thread(demo.getConcurrencyCheckTask());
thread1.start();
Thread thread2 = new Thread(demo.getConcurrencyCheckTask());
thread2.start();
thread1.join();
thread2.join();
int actualCounter = demo.counter.intValue();
int expectedCount = INC_COUNT * 2;
if (actualCounter != expectedCount) {
// 在我的开发机上,几乎必现!即使counter上加了volatile。(简单安全的解法:使用AtomicInteger)
System.err.printf("Fuck! Got wrong count!! actual %s, expected: %s.", actualCounter, expectedCount);
} else {
System.out.println("Wow... Got right count!");
}
}
ConcurrencyCheckTask getConcurrencyCheckTask() {
return new ConcurrencyCheckTask();
}
private class ConcurrencyCheckTask implements Runnable {
@Override
public void run() {
for (int i = 0; i < INC_COUNT; ++i) {
counter.incrementAndGet();
}
}
}
}