無同步的併發計數結果不對

Demo類com.oldratlee.fucking.concurrency.WrongCounterDemojava

Demo說明

主線程中開啓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();
            }
        }
    }
}
相關文章
相關標籤/搜索