设计模式--单例模式--DCL

本文深入探讨了3DCL懒汉式(双重检测)单例模式的实现原理,对比了其与普通懒汉式的差异,重点讲解了如何通过volatile关键字解决指令重排带来的线程安全问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3 DCL懒汉式 (双重检测)

DCL是在懒汉式的基础上修改的

懒汉式

public class SingletonDemo2 {
//优缺点
//    优  线程安全  可以延迟加载 
//    缺点  效率不高
    //    私有化构造器
    private SingletonDemo2() {}
    //    创建但不初始化
    private static SingletonDemo2 INSTANCE;
    public static synchronized SingletonDemo2 getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new SingletonDemo2();
        }
        return INSTANCE;
    }
}

有synchronized可以保证线程安全 但是只有每次同步请求 会造成性能上的浪费

那我们吧 synchronized 放到里面 并顺带加一个判断

public class SingletonDemo3 {
    //    1. 私有化构造器
    private SingletonDemo3() {}
    // 2.初始化单例
    private static SingletonDemo3 instance ;
//    3.全局访问方法
    public static SingletonDemo3 getInstance() {
        if (instance == null) {
            synchronized (SingletonDemo3.class) {
                if (instance == null) {
                    instance = new SingletonDemo3();
                }
            }
        }
        return instance;
    }
}

现在假设有两个线程 线程一 线程二

线程一抢先进入getInstance()方法 并获取到了类锁 开始执行 synchronized 的代码块儿 这时候instance 是空的 要new给线程一

这时候 创建实例 会有几个过程

  • 分配内存
  • 初始化构造器
  • 指向内存地址 这时候instance才不是空

由于指令重排 可能这三个步骤就会不是这样 可能变成这样

  • 分内存
  • 指向内存地址
  • 初始化构造器

可看到 没有执行到 初始化构造器 的时候instance已经不为空了 但是又没有初始化 如果 这时候线程二进到了getInstance() 那么就会直接判定instance不为空 那就直接被线程二拿走用了 但是这时候又没有初始化 所以

就会报错

给instance加一个volatile关键字


public class SingletonDemo3 {
    //    1. 私有化构造器
    private SingletonDemo3() {}
    // 2.初始化单例
    private static volatile SingletonDemo3 instance ;
//    3.全局访问方法
    public static SingletonDemo3 getInstance() {
        if (instance == null) {
            synchronized (SingletonDemo3.class) {
                if (instance == null) {
                    instance = new SingletonDemo3();
                }
            }
        }
        return instance;
    }
}

就可以了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值