常看到在易变域上的同步代码,并且写的同学会很自然觉得这样是安全和正确的。
# 问题分析见文章链接:,对应的英文文章: Demo类。Demo说明
主线程中开启2个任务线程执行addListener
。主线程最终结果检查。
问题说明
最终Listener
的个数不对。
快速运行
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 Listlisteners = new CopyOnWriteArrayList (); 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 results = new ArrayList (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!"); } }}