懒汉式双重检查就线程安全了吗?

先说结果:线程不安全

public class Test{                                                       //1 
 
    private static Singleton singleton;                                  //2
 
    public static Singleton getSingleton() {                             //3
 
        //如果第一个线程获取到了单例的实例对象, 
        //后面的线程再获取实例的时候不需要进入同步代码块中了
        if (singleton == null) {                                         //4 第一次检查
            // 同步代码块用的锁是单例的字节码文件对象,且只能用这个锁         
            synchronized (Singleton.class) {                             //5 加锁
                if (singleton == null) {                                 //6 第二次检查
                    singleton = new Singleton();                         //7 问题出现了!
                }                                                        //8
            }                                                            //9
        }                                                                //10
        return singleton;                                                //11
    }
}

诺,执行到第7行的时候,就是创建对象,

singleton = new Singleton(); 这一行可以分解为如下的3行伪代码:

  • memory = allocate(); //1,分配对象的内存空间

  • ctorInstance(memory); //2,初始化对象

  • instance = memory; //3,设置instance指向刚分配的内存地址

以上三行代码,2,3步可能会被重排序,如果指令重排序之后,发生的情况如下:

  • memory = allocate(); //1,分配对象的内存空间

  • instance = memory; //3,设置instance指向刚分配的内存地址;注意!此时对象还没有被初始化!

  • ctorInstance(memory); //2,初始化对象

重排序之后的执行顺序:

这时候就找到问题了,如果发生指令重排序,线程B有可能在第4行判断singleton不为null,之后线程B开始访问singleton引用的对象,而此时这个对象还没有被A线程初始化。这不就出问题了?

知道了问题,怎么解决是接下来的问题,思路如下:

1,不允许2,3步重排序

2,即使2,3重排序,那这个过程不让其他线程知晓,对外显示为原子操作。

所以懒汉式就需要使用volatile修饰对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值