单例模式--双重检验锁真的线程安全吗

之前我们使用单例模式经常会用到两种方式,一种是懒汉是双重锁,一种是静态内部类,可以看下这个深入理解单例模式:静态内部类单例原理,但是其中用到的双重锁懒汉模式 其实并非是真正的线程安全的。

例如这样:

public static Singleton getSingleton() {  
  if (instance == null) {                       

        synchronized (Singleton.class) {          
             if (instance == null) {               

                instance = new Singleton();

            }

        }

    }    return instance ;

}


我们看到,在同步代码块的内部和外部都判断了instance == null,这时因为,可能会有多个线程同时进入到同步代码块外的if判断中,如果在同步代码块内部不进行判空的话,可能会初始化多个实例。

问题所在

这种写法看似完美无缺,但它却是有问题的,或者说它并不担保一定完美无缺。主要原因在于instance = new Singleton();并不是原子性的操作。

创建一个对象可以分为三部:

1.分配对象的内存空间

2.初始化对象

3.设置instance指向刚分配的内存地址

但是,2、3部之间,可能会被重排序,造成创建对象顺序变为1-3-2.试想一个场景:

线程A第一次创建对象Singleton,对象创建顺序为1-3-2;

当给instance分配完内存后,这时来了一个线程B调用了getSingleton()方法

这时候进行instance == null的判断,发现instance并不为null。

但注意这时候instance并没有初始化对象,线程B则会将这个未初始化完成的对象返回。那B线程使用instance时就可能会出现问题,这就是双重检查锁问题所在。

使用volatile

对于上述的问题,我们可以通过把instance声明为volatile型来解决

public class Singleton{

private volatile static Singleton instance;

public static Singleton getSingleton() {  
  if (instance == null) {                       

      synchronized (Singleton.class) {      
      if (instance == null) {               
           instance = new Singleton();

            }

        }

    }   
 return instance ;

}

}

但是必须在JDK5版本以上使用。

参考:

    http://www.imooc.com/article/282271

发布了68 篇原创文章 · 获赞 13 · 访问量 6万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览