双重检查锁实现单例模式的线程安全问题
一、结论
双重校验锁的单例模式代码如下:
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getSingleton() {
if (singleton == null) { // 1
synchronized (Singleton.class) { // 2
if (singleton == null) { // 3
singleton = new Singleton(); // 4
}
}
}
return singleton;
}
}
假设有两个线程AB同时访问上面这段代码,它并不能保证线程安全。
二、问题说明
1、指令重排序的简单说明
重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。
(1)编译器指令重排序
编译器在不改变程序 执行结果的前提下,可以对程序的执行顺序进行优化重新排序
(2) 处理器指令重排序
参考:https://blog.csdn.net/javazejian/article/details/72772461 (处理器指令重排)
2、 对象创建过程
分为三步,如下图:
我们认为程序应该是按照1、2、3的步骤走下去,但实际上可能不是这样的,这里编译器和处理器可能会对2、3步的执行顺序进行重排序,即先将对象的引用指向内存空间,实际上A线程返回的是没有初始化的对象,然后B线程访问上面这段代码,判断if (singleton == null) { // 1 就为false,它会认为Singleton类已经实例化,问题就出在这里。
重排序后A 、B线程执行时序图如下:
三、解决方案
1、不允许对象创建过程中2、3步发生指令重排序 (基于volatile的解决方案)
即将Singleton声明时加上volatile,volatile关键字可以保证内存可见性和禁止指令重排序,关于volatile参见https://blog.csdn.net/javazejian/article/details/72772461 (volatile内存语义)
修改后的代码:
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {}
public static Singleton getSingleton() {
if (singleton == null) { // 1
synchronized (Singleton.class) { // 2
if (singleton == null) { // 3
singleton = new Singleton(); // 4
}
}
}
return singleton;
}
}
Singleton属性被加上volatile后,4中对象创建过程的2、3两步在多线程环境下就被禁止重排序,这样就能保证线程安全。
2、允许对象创建过程中2、3重排序,但不允许其他线程看到这个重排序 (基于类初始化的解决方案)
JVM在类的初始化阶段,会执行类的初始化。在执行类的初始化期间,JVM会获取一个锁,这个锁可以同步多个线程对同一个类的初始化。基于这个特性修改代码如下:
public class Singleton {
private static class SingletonHolder{
public static Singleton singleton = new Singleton();
}
public static Singleton getSingleton(){
return SingletonHolder.singleton;
}
}
多线程访问上面这段程序的时序图如下:
参考资料:
1、https://blog.csdn.net/javazejian/article/details/72772461
2、《Java并发编程的艺术》第三章 Java内存模型
说明:菜鸟一枚,第一次发技术博客,如有错误或者写的不好的地方欢迎大家指正。
转载于:https://www.cnblogs.com/-Marksman/p/9219274.html
双重检查锁实现单例模式的线程安全问题相关推荐
- 双重检查锁与单例模式
单例模式是比较常见的一种设计模式,在开发实践中经常看到它的身影,它有很多种实现方式,曾经有人在一篇文章中列举了十几种实现方式,比如饿汉式.懒汉式.双重检查锁.枚举...等等,程序员应该都熟悉这些常见的 ...
- java双重检查锁单例真的线程安全吗?
相信大多数同学在面试当中都遇到过手写单例模式的题目,那么如何写一个完美的单例是面试者需要深究的问题,因为一个严谨的单例模式说不定就直接决定了面试结果,今天我们就要来讲讲看似线程安全的双重检查锁单例模 ...
- 单例模式之双重检查锁(double check locking)的发展历程
不安全的单例 没有注意过多线程安全问题的时候,我们的单例可能是这样的: public final class Singleton {private static Singleton instance; ...
- java并发编程(二十六)——单例模式的双重检查锁模式为什么必须加 volatile?
前言 本文我们从一个问题出发来进行探究关于volatile的应用. 问题:单例模式的双重检查锁模式为什么必须加 volatile? 什么是单例模式 单例模式指的是,保证一个类只有一个实例,并且提供一个 ...
- 双重检查锁模式导致空指针
今天遇到一个问题:莫名奇妙报了个空指针,后来发现原来单例模式在高并发下引起的: 双重检查锁模式的一般实现: 双重检查锁模式解决了单例.性能.线程安全问题,但是这种写法同样存在问题:在多线程的情况下,可 ...
- 双重检查锁,原来是这样演变来的,你了解吗
最近在看Nacos的源代码时,发现多处都使用了"双重检查锁"的机制,算是非常好的实践案例.这篇文章就着案例来分析一下双重检查锁的使用以及优势所在,目的就是让你的代码格调更加高一个层 ...
- Java中的双重检查锁(double checked locking)
起因 在实现单例模式时,如果未考虑多线程的情况,很容易写出下面的代码(也不能说是错误的): public class Singleton {private static Singleton uniqu ...
- java 双重检查锁_Java中可怕的双重检查锁定习惯用法
java 双重检查锁 本文讨论的问题不是新问题,但即使是经验丰富的开发人员也仍然很棘手. 单例模式是常见的编程习惯用法. 但是,当与多个线程一起使用时,必须进行某种类型的同步,以免破坏代码. 在相关文 ...
- 双重检查锁定及单例模式
双重检查锁定及单例模式 转载 http://www.ibm.com/developerworks/cn/java/j-dcl. ...
最新文章
- 新记录诞生,腾讯云2分31秒打破ImageNet训练记录
- struts中简单的校验
- Flink CDC 2.0 正式发布,详解核心改进
- 实现Jitsi SFU自动关闭/启动视频层
- linux解决病毒系列之一,删除十字符libudev.so病毒文件
- 学成在线--23.课程图片管理(上传图片)
- 专访《程序员的三门课》李伟山:从程序员到技术总监的修炼秘籍!
- jvm 堆外内存_jvm┃java内存区域,跳槽大厂必会知识点
- JavaWeb项目开发案例精粹-第6章报价管理系统-001需求分析及设计
- [转载] pandas入门:Series、DataFrame、Index基本操作都有了!
- 计算机ers,读博、国企、互联网公司该如何选择?
- Tomcat5.5中配置虚拟路径
- js实现将网页下载为pdf
- 活字格企业Web应用生成器荣获2017年度优秀软件产品
- 教你流程化梳理外贸工作(附18个全流程邮件模板分享)
- 第二章 让你的kali系统变得更好用
- python算术平方根_Python 平方根
- 让计算机休眠的命令,电脑怎么取消休眠?关闭休眠命令是什么?
- PROBOT_G603双臂GAZEBO+MoveIt!仿真中配置手眼相机和夹爪
- python实战(一)Python爬取猫眼评分排行前100电影及简单数据分析可视化
热门文章
- git push 提交时显示 Empty reply from server的解决办法
- H5学习之旅-H5列表(8)
- 第2章 数字之魅——快速寻找满足条件的两个数
- [原创]Enterprise Architecture V7.5 C++代码生成时,头文件中函数声明没有注释,CPP中函数定义却有注释。...
- 大学生学编程系列」第五篇:自学编程需要多久才能找到工作?
- java: cannot execute binary file 如果遇到这个错,一般是操作系统位数出问题了。
- Pokemon Go将在日本发布 网络安全公司呼吁防范虚假软件
- 雪碧图sprity 合并多图使用心得
- Windows Phone 7实现图片数据绑定
- 台湾高僧称游戏中杀人是罪业死后要下地狱