再谈双重检查成例的懒汉式单例模式
阎宏在《Java与模式》强烈建议大家不要再花时间在实现双重检查成例上,理由是:
“令人吃惊的是,在C语言里得到普遍应用的双重检查成例在多数的Java语言编译器里并不成立。上面使用了双重检查成例的“懒汉式”单例类,不能工作的基本原因在于,在Java编译器中,LazySingleton类的初始化与m_instance变量赋值的顺序不可预料。如果一个线程在没有同步化的条件下读取m_instance引用,并调用这个对象的方法的话,可能会发现对象的初始化过程尚未完成,从而造成崩溃。”
1 public class LazySingleton
2 {
3 private static LazySingleton m_instance = null;
4 private LazySingleton(){}
5 public static LazySingleton getInstance()
6 {
7 if(m_instance == null)
8 {
9 synchronized(LazySingleton.class)
10 {
11 if(m_instance == null)
12 {
13 m_instance = new LazySingleton();
14 }
15 }
16 }
17 return m_instance;
18 }
19}
我看了不是很明白,是不是指new LazySingleton()在执行构造函数和m_instance = ....这个赋值语句的顺序不确定。可能会出现new LazySingleton() 先分配好内存地址,然的执行了 m_instance = “内存地址”,再执行构造函数里的代码,这样会造成m_instance先被赋了值。其它线程一量这时候访问第7行就会出错。如果是这样,我们是不是可以改成以下:
1 public class LazySingleton
2 {
3 private static LazySingleton m_instance = null;
4 private LazySingleton(){}
5 public static LazySingleton getInstance()
6 {
7 if(m_instance == null)
8 {
9 synchronized(LazySingleton.class)
10 {
11 if(m_instance == null)
12 {
13 LazySingleton temp = new LazySingleton();
14 m_instance = temp;
15 }
16 }
17 }
18 return m_instance;
19 }
20}
实在是不太清楚,请高手指教。