0Ch],0F84030h
可以看到,赋值完成在初始化之前,而这是JLS允许的。
另一种情形是,假设线程一安稳地完成Singleton对象的初始化,退出了同步块,并同步了和本地内存和主存。线程二来了,看到一个非空的引用,拿走。注意线程二没有执行一个Read Barrier,因为它根本就没进后面的同步块。所以很有可能此时它看到的数据是陈旧的。
还有很多人根据已知的几种提出了一个又一个fix的方法,但最终还是出现了更多的问题。可以参阅[3]中的介绍。
[5]中还说明了即使把instance字段声明为volatile还是无法避免错误的原因。
由此可见,安全的Singleton的构造一般只有两种方法,一是在类载入时就创建该实例,二是使用性能较差的synchronized方法。
本文来自ZelluX的BlogJava博客《Singleton模式与双检测锁定(DCL) 》一文
参考资料: [1] Java Language Specification, Second Edition, 第17章介绍了Java中线程和内存交互关系的具体细节。 [2] out-of-order与cache的介绍可以参阅Computer System, A Programmer's Perspective的第四、五章。 [3] The "Double-Checked Locking is Broken" Declaration [4] Synchronization and the Java Memory Model [5] Double-checked locking: Clever, but broken [6] Holub on Patterns, Learning Design Patterns by Looking at Code |