面试官竟然不知道Java单例模式双重检验锁一定要加volatile!

举报
JavaEdge 发表于 2021/06/04 00:55:22 2021/06/04
【摘要】 线程安全的单例模式本质上其实也是单次初始化,所以可以用Balking模式: class Singleton{ private static Singleton singleton; //构造方法私有化 private Singleton(){} //获取实例(单例) public synchronized static Singleton ge...

线程安全的单例模式本质上其实也是单次初始化,所以可以用Balking模式:

class Singleton{
  private static Singleton singleton;
  //构造方法私有化  
  private Singleton(){}
  //获取实例(单例)
  public synchronized static Singleton getInstance(){ if(singleton == null){ singleton=new Singleton(); } return singleton;
  }
}

  
 

这个实现但是性能却很差,因为互斥锁synchronized将getInstance()方法串行化了,那有没有办法可以优化一下它的性能呢?

办法当然是有的,那就是DCL,一旦Singleton对象被成功创建之后,就不会执行synchronized(Singleton.class){},即此时getInstance()方法的执行路径是无锁的,从而解决了性能问题。
使用volatile禁止编译优化。获取锁后的二次检查,出于安全性。

class Singleton{
  private static volatile Singleton singleton;
  //构造方法私有化  
  private Singleton() {}
  //获取实例(单例)
  public static Singleton getInstance() { //第一次检查 if(singleton==null){ synchronize{Singleton.class){ //获取锁后二次检查 if(singleton==null){ singleton=new Singleton(); } } } return singleton;
  }
}

  
 

也可以使用DCL优化性能,双重检查中的第一次检查,完全是出于对性能的考量:避免执行加锁操作,因为加锁操作很耗时。而加锁之后的二次检查,则是出于对安全性负责。双重检查方案在优化加锁性能方面经常用到,ReadWriteLock实现缓存按需加载功能时,也用DCL。



对于 T t = new T();
其实有如下字节码指令完成

_new 'org/openjdk/jol/T'
dup
INVOKESPECIAL org/openjdk/jol/T.<init> ()V
astore 1
return

  
 

线程一 new 到一半时,m=0,发生重排序
这时线程 2 来了!看到 t 已经指向了一个半初始化的实例了!

这个概率很小,但是并发如淘宝,都是可能发生的!所以必须要加!

文章来源: javaedge.blog.csdn.net,作者:JavaEdge.,版权归原作者所有,如需转载,请联系作者。

原文链接:javaedge.blog.csdn.net/article/details/105319129

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。