首页 > 编程语言 > 详细

解释单例模式中的 双重锁为什么是线程不安全的

时间:2019-08-20 17:14:02      阅读:92      评论:0      收藏:0      [点我收藏+]

一丶 双排序的单例模式代码如下

public class SingletonSofeLanEx {

/**
* 如果要保证是单例
* 构造函数一定是私有的
*/
private SingletonSofeLanEx() {
//DO SOME SING
}

public static SingletonSofeLanEx instace = null;

//静态的工程方式,同一时刻只有一个线程访问
public static SingletonSofeLanEx getInstace() {
if (null == instace) { //#2:B线程 看到instace已经不是null啦,就直接return啦,然而此刻 第三步的 初始化还没进行,使用这个实例肯定会有
synchronized (SingletonSofeLanEx.class){
if (instace == null){
instace = new SingletonSofeLanEx(); //#1:A线程 执行到指令重排的 第二步也就是3,分配内存
}
}
}
return instace;
}

}

二丶 解释为什么是线程不安全的
  我来说一下 SingletonSofeLanEx 在CPU当中的工作流程,总共分为三步
   1:memory = allocate() 分配对象内存空间
2:ctorInstance() 初始化对象
3: instace = memory 设置instace分配的内存
 
jvm和cpu优化会指令重排,上面顺序会变成1,3,2
单线程环境下,此顺序是没有问题,2,3 前后没有依赖性
   但是在多线程情况下会有这种情况,具体看#1,#2

三丶 那么如何解决呢,这里的思路是防止重排序,使用 volatile 可防止jvm跟cpu进行重排序指令
    最终代码

public class SingletonSofeLanEx {

/**
* 如果要保证是单例
* 构造函数一定是私有的
*/
private SingletonSofeLanEx() {
//实力的时候运行一些计算
}

//1:memory = allocate() 分配对象内存空间
//2:ctorInstance() 初始化对象
//3: instace = memory 设置instace分配的内存

//jvm和cpu优化重新指令重排,上面会变成1,3,2
public volatile static SingletonSofeLanEx instace = null;


//静态的工程方式,同一时刻只有一个线程访问
public static SingletonSofeLanEx getInstace() {
if (null == instace) { //2:B线程 看到instace已经不是null啦,就直接return啦,然后第三步的 初始化还没进行
synchronized (SingletonSofeLanEx.class){
if (instace == null){
instace = new SingletonSofeLanEx(); //1:A线程 执行到指令重排的 第二步也就是3,分配内存
}
}
}
return instace;
}

}


解释单例模式中的 双重锁为什么是线程不安全的

原文:https://www.cnblogs.com/quzhongren/p/11383998.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!