Java双重检查锁的单利模式安全吗

发布时间:2021-06-22 16:00:25 作者:chen
来源:亿速云 阅读:129

这篇文章主要讲解了“Java双重检查锁的单利模式安全吗”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java双重检查锁的单利模式安全吗”吧!

相信大多数同学在面试当中都遇到过手写单例模式的题目,那么如何写一个完美的单例是面试者需要深究的问题,因为一个严谨的单例模式说不定就直接决定了面试结果,今天我们就要来讲讲看似线程安全的双重检查锁单例模式中可能会出现的指令重排问题。

双重检查锁单例模式

乍一看下面单例模式没啥问题,还加了同步锁保证线程安全,从表面上看确实看不出啥问题,当在同一时间多个线程同时执行该单例时就会出现JVM指令重排的问题,从而可能导致某一个线程获取的single对象未初始化对象。

public class Single {   private static Single single;    private Single() {  }    public static Single getInstance() {   if(null == single) {    synchronized (Single.class) {     if(null == single) {      single = new Single();     }    }   }   return single;  } }

问题前因后果

其实single = new  Single()这段代码并不具备原子性,从代码层面上来说确实没问题,但是如果了解JVM指令的就知道其实在执行这句代码的时候在JVM中是需要执行三个指令来完成的,如下:

//1:分配对象的内存空间 memory = allocate();  //2:初始化对象 ctorInstance(memory);  //3:设置instance指向刚分配的内存地址 instance = memory;

看到上面指令重排的解释之后,那么我们来回顾一下未加volatile修饰符的单例为何会出现问题。假设有A、B两个线程去调用该单例方法,当A线程执行到single  = new Single()时,如果编译器和处理器对指令重新排序,指令重排后:

//1:分配对象的内存空间 memory = allocate();  //3:设置instance指向刚分配的内存地址,此时对象还没被初始化 instance = memory;  //2:初始化对象 ctorInstance(memory);

当A线程执行到第二步(3:设置instance指向刚分配的内存地址,此时对象还没被初始化)变量single指向内存地址之后就不为null了,此时B线程进入第一个if,由于single已经不为null了,那么就不会执行到同步代码块,而是直接返回未初始化对象的变量single,从而导致后续代码报错。

解决方案

问题也搞清楚了,接下来我们就来看下如何解决这个问题。解决问题的关键就在于volatile关键字,原因就在于它的可见性:

写volatile修饰的变量时,JMM会把本地内存中值刷新到主内存 读

volatile修饰的变量时,JMM会设置本地内存无效

在多线程环境下,一个线程对共享变量的操作对其他线程是不可见的,Java提供了volatile来保证可见性,当一个变量被volatile修饰后,表示着线程本地内存无效,当一个线程修改共享变量后他会立即被更新到主内存中,其他线程读取共享变量时,会直接从主内存中读取。

当然,synchronize和Lock都可以保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。

更正后的单例

对比上面单例,下面单例在私有静态变量single前面加了修饰符volatile能够防止JVM指令重排,从而解决了single对象可能出现成员变量未初始化的问题。

public class Single {   private volatile static Single single;    private Single() {  }    public static Single getInstance() {   if(null == single) {    synchronized (Single.class) {     if(null == single) {      single = new Single();     }    }   }   return single;  } }

感谢各位的阅读,以上就是“Java双重检查锁的单利模式安全吗”的内容了,经过本文的学习后,相信大家对Java双重检查锁的单利模式安全吗这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

推荐阅读:
  1. Python单利模式,简单工厂实现,import自定义模块
  2. 双重检查锁单例模式为什么要用volatile关键字?

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:使用CompletableFuture怎么实现并发编程

下一篇:Spring中@Transactional事务不生效如何解决

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》