单例模式之DCL分析

今天,分享一下单例模式之DCL分析。

public class SingletonDemo {
    private static volatile SingletonDemo singletonDemo = null;
    private SingletonDemo(){
        System.out.println("double check Lock双端检锁机制");
    }
    //DCL(double check Lock双端检锁机制)
    public static SingletonDemo getSingleton(){
        if (singletonDemo==null){
            synchronized (SingletonDemo.class){
                if(singletonDemo==null){
                    singletonDemo = new SingletonDemo();
                }
            }

        }
        return singletonDemo;
    }
    public static void main(String[] args) {
    }
}

注意:DCL(double check lock)双端检锁机制不一定线程安全,因为有指令重排的存在,加入volatile可以解决,因为volatile可以禁止指令重排。

问:为什么DCL不一定线程安全?

分析:当某一个线程执行第一次检测,读取到的instancce不为null时,instance的引用对象可能还没有完全初始化。

instance = new SingleonDemo()可以分为以下3步完成(伪代码)

1、分配对象内存空间:memory = allocate();

2、初始化对象:instance(memory);

3、设置instance指向刚分配内存地址(此时instanc!=null):instance = memory;

以上步骤2和步骤3不存在数据依赖关系,而且无论重排还是重排后程序的执行结果哎单线程中并没有改变,因此这种重排优化是允许的 :1->3->2,即

1、分配对象内存空间:memory = allocate();

2、设置instance指向刚分配内存地址(此时instanc!=null,但是对象还没有初始化完成!):instance = memory;

3、初始化对象:instance(memory);

但是指令重排只会保证串行语义的执行的一致(单线程),并不关心多个线程的语义一致性,所以当一条线程访问instance不为null时,由于instance实例未必初始化完成,也就造就了线程安全问题。

努力奋斗,不负韶华!

 

 

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值