锁定老帖子 主题:再请教双重检查锁定DCL的问题
精华帖 (0) :: 良好帖 (11) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-01-21
public class LazySingleton { private static LazySingleton m_instance = null; private LazySingleton() { } public static LazySingleton getInstance() { if (m_instance == null) { synchronized (LazySingleton.class) { if (m_instance == null) { m_instance = new LazySingleton(); } } } return m_instance; } } “在Java编译器中,LazySingleton类的初始化与m_instance变量赋值的顺序不可预料。如果一个线程在没有同步化的条件下读取m_instance引用,并调用这个对象的方法的话,可能会发现对象的初始化过程尚未完成,从而造成崩溃。” 可是通过查看编译后的字节码: ...... 10 monitorenter 11 getstatic #10 <my/LazySingleton.m_instance> 14 ifnonnull 27 (+13) 17 new #1 <my/LazySingleton> 20 dup 21 invokespecial #20 <my/LazySingleton.<init>> 24 putstatic #10 <my/LazySingleton.m_instance> 27 aload_0 28 monitorexit ...... 第21行和22行表明,LazySingleton对象的初始化,是在m_instance变量赋值之前。 至少对于Java编译器,这个次序是明确的,并不是不可预料的。 阎宏给出的理由很容易理解,也更希望是原因是这样的,可实际情况并非如此。 谁能从虚拟机或CPU执行的角度解释一下这个问题吗? 谢谢 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-01-21
这个和具体用的jvm有关,不是所有的jvm都能保证这个顺序!
|
|
返回顶楼 | |
发表时间:2008-01-21
这应该和操作系统有关,在linux下线程的执行循序是无序的,好像是这么个意思
|
|
返回顶楼 | |
发表时间:2008-01-21
java 5的spec已经修正了这个问题。不过用volatile的话,jvm的实现还是有些不标准的。
只要LazySingleton的所有instance field都是final的话(immutable),就肯定保证成功。 |
|
返回顶楼 | |
发表时间:2008-01-21
编译后的字节码的顺序是对的,但是jvm执行的时候可能会重排序(reordering),这才是问题所在。这个问题可以通过将m_instance 声明为volatile解决,不过volatile的语义在jdk5以前并没有被正确实现。
|
|
返回顶楼 | |
发表时间:2008-01-22
学习了,以前没注意到。
下面这样是不是也应该没有问题? public class LazySingleton { private static LazySingleton m_instance = null; private LazySingleton() { } public static LazySingleton getInstance() { if (m_instance == null) { synchronized (LazySingleton.class) { if (m_instance == null) { LazySingleton instance = new LazySingleton(); m_instance = instance; } } } return m_instance; } } |
|
返回顶楼 | |
发表时间:2008-01-22
ls很有趣 都构造器private且 方法也static了,你还在11行
LazySingleton instance = new LazySingleton(); |
|
返回顶楼 | |
发表时间:2008-01-22
jomper 写道 ls很有趣 都构造器private且 方法也static了,你还在11行
LazySingleton instance = new LazySingleton(); 我和楼主写的没有什么区别,只是多个本地变量。。。 虽然构造方法私有,不过是本类中调用的。 虽然是静态方法,不过做实例化也是很正常的。 |
|
返回顶楼 | |
发表时间:2008-01-22
DCL的一个总结,最后一个代码例子比较有意思.
http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#dcl |
|
返回顶楼 | |
发表时间:2008-01-22
neuzhujf 写道 学习了,以前没注意到。
下面这样是不是也应该没有问题? public class LazySingleton { private static LazySingleton m_instance = null; private LazySingleton() { } public static LazySingleton getInstance() { if (m_instance == null) { synchronized (LazySingleton.class) { if (m_instance == null) { LazySingleton instance = new LazySingleton(); m_instance = instance; } } } return m_instance; } } 说实话,你的代码和lz的没有任何区别,原先有的错误还是存在。 简单的解决方案就是将m_instance声明为volatile,在JDK1.5之后没有问题。 |
|
返回顶楼 | |