双重检查锁实现单例模式的线程安全问题
2018-07-11 03:31:24来源:博客园 阅读 ()
一、结论
双重校验锁的单例模式代码如下:
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内存模型
说明:菜鸟一枚,第一次发技术博客,如有错误或者写的不好的地方欢迎大家指正。
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- DES/3DES/AES 三种对称加密算法实现 2020-06-11
- SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 后 2020-06-10
- Spring Boot 实现定时任务的 4 种方式 2020-06-10
- JSP+SSH+Mysql+DBCP实现的租车系统 2020-06-09
- Java实现的三种字符串反转 2020-06-09
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash