Demo類com.oldratlee.fucking.concurrency.WrongCounterDemo
。java
主線程中開啓2個任務線程執行併發遞增計數。主線程最終結果檢查。git
計數值不對。github
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(); } } } }