還沒理解,有待補充---易變域上的同步

常看到在易變域上的同步代碼,而且寫的同窗會很天然以爲這樣是安全和正確的。
# 問題分析見文章連接:在易變域上的同步,對應的英文文章:Synchronization on mutable fields
Demo類com.oldratlee.fucking.concurrency.SynchronizationOnMutableFieldDemojava

Demo說明

主線程中開啓2個任務線程執行addListener。主線程最終結果檢查。git

問題說明

最終Listener的個數不對。github

快速運行

mvn compile exec:java -Dexec.mainClass=com.oldratlee.fucking.concurrency.SynchronizationOnMutableFieldDemo

具體demo:

public class SynchronizationOnMutableFieldDemo {
    static final int ADD_COUNT = 10000;

    static class Listener {
        // stub class
    }

    private volatile List<Listener> listeners = new CopyOnWriteArrayList<Listener>();

    public static void main(String[] args) throws Exception {
        SynchronizationOnMutableFieldDemo demo = new SynchronizationOnMutableFieldDemo();

        Thread thread1 = new Thread(demo.getConcurrencyCheckTask());
        thread1.start();
        Thread thread2 = new Thread(demo.getConcurrencyCheckTask());
        thread2.start();

        thread1.join();
        thread2.join();

        int actualSize = demo.listeners.size();
        int expectedSize = ADD_COUNT * 2;
        if (actualSize != expectedSize) {
            // 在個人開發機上,幾乎必現!(簡單安全的解法:final List字段並用併發安全的List,如CopyOnWriteArrayList)
            System.err.printf("Fuck! Lost update on mutable field! actual %s expected %s.\n", actualSize, expectedSize);
        } else {
            System.out.println("Emm... Got right answer!!");
        }
    }

    public void addListener(Listener listener) {
        synchronized (listeners) {
            List<Listener> results = new ArrayList<Listener>(listeners);
            results.add(listener);
            listeners = results;
        }
    }

    ConcurrencyCheckTask getConcurrencyCheckTask() {
        return new ConcurrencyCheckTask();
    }

    private class ConcurrencyCheckTask implements Runnable {
        @Override
        public void run() {
            System.out.println("ConcurrencyCheckTask started!");
            for (int i = 0; i < ADD_COUNT; ++i) {
                addListener(new Listener());
            }
            System.out.println("ConcurrencyCheckTask stopped!");
        }
    }
}
相關文章
相關標籤/搜索