DCL问题——单例懒汉式加载双重锁检查

🌈hello,你好鸭,我是Ethan,西安电子科技大学大三在读,很高兴你能来阅读。

✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!

🔥个人主页:Ethan Yankang
🔥推荐:史上最强八股文||一分钟看完我的几百篇博客

🔥温馨提示:划到文末发现专栏彩蛋   点击这里直接传送

🔥本篇概览:详细讲解了Java并发编程中的DCL问题。🌈⭕🔥


【计算机领域一切迷惑的源头都是基本概念的模糊,算法

除外】


👉Java并发编程专栏


🌈引出:

DCL又称为双重检查锁定(Double Check Lock),来源于单例模式的懒汉加载问题。当实现一个

单例类时,在选择懒汉延迟加载时,就会用到DCL保证创建的唯一性。


O、直击全貌

下面的双重if判断就是DCL,这就是双重检查!!

防止多个线程进入了第一次检查,后面又都进入第二道防线,创建多个对象。 

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

一、DCL 的目的和基本原理

  1. 目的

    • 在多线程环境中,确保一个类只有一个实例,并且在首次使用时才进行实例化,同时尽量减少同步带来的性能开销。
  2. 基本原理

    • 第一次检查:在获取实例的方法中,首先进行一次非同步的检查,判断实例是否已经被创建。如果实例已经存在,直接返回该实例,避免进入同步块带来的开销。
    • 同步块:如果第一次检查发现实例不存在,那么进入同步块。同步块的作用是确保在多线程环境下,只有一个线程能够进行实例化操作。
    • 第二次检查:在同步块内部再次进行检查,确认实例是否已经在进入同步块之前被其他线程创建。如果已经创建,直接返回实例;如果没有创建,才进行实例化操作。

二、DCL 可能出现的问题

  1. 指令重排序问题

    • 在 Java 内存模型中,为了提高性能,编译器和处理器可能会对指令进行重排序。在单例模式的 DCL 实现中,如果没有正确处理指令重排序,可能会导致一个未完全初始化的对象被其他线程访问。
    • 例如,在对象的初始化过程中,可能会先分配内存空间,然后进行部分初始化,最后再将引用指向这个内存空间。如果在这个过程中发生了指令重排序,其他线程可能在对象还未完全初始化时就获取到了该对象的引用,从而导致错误的结果。

  1. 可见性问题

    • 在多线程环境中,不同线程对共享变量的可见性是一个关键问题。如果没有正确处理可见性,一个线程对共享变量的修改可能无法及时被其他线程看到。
    • 在 DCL 中,如果没有使用适当的关键字(如volatile)来确保实例变量的可见性,其他线程可能无法及时看到实例已经被创建,从而导致重复创建实例或者其他错误行为。

三、解决 DCL 问题的方法

  1. 使用volatile关键字
    • volatile关键字可以确保对变量的写操作立即对其他线程可见,并且禁止指令重排序。在 DCL 实现单例模式中,将实例变量声明为volatile可以解决指令重排序和可见性问题。例如本篇开章的例子。

四、其他实现单例模式的方法

  • 除了 DCL,还有其他一些实现单例模式的方法,如饿汉式单例模式、静态内部类单例模式等。这些方法在不同的场景下可能有不同的优缺点。
  • 饿汉式单例模式在类加载时就创建实例,不存在线程安全问题,但可能会造成资源的浪费如果实例在程序运行过程中不一定会被使用。
  • 静态内部类单例模式(IoDH)在第一次调用时才创建实例,既保证了线程安全,又避免了饿汉式的资源浪费问题。(通常是也算最优解!)
  • 枚举类,通常认为是最优解【详见此链接

五、总结

        总之,在使用 DCL 时需要特别注意指令重排序和可见性问题,通过正确使用volatile关键字等方法可以确保 DCL 的正确性。同时,也可以考虑其他实现单例模式的方法,根据具体的应用场景选择最合适的方式。



💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖

热门专栏推荐

🌈🌈计算机科学入门系列                     关注走一波💕💕

🌈🌈CSAPP深入理解计算机原理        关注走一波💕💕

🌈🌈微服务项目之黑马头条                 关注走一波💕💕

🌈🌈redis深度项目之黑马点评            关注走一波💕💕

🌈🌈JAVA面试八股文系列专栏           关注走一波💕💕

🌈🌈JAVA基础试题集精讲                  关注走一波💕💕   

🌈🌈代码随想录精讲200题                  关注走一波💕💕


总栏

🌈🌈JAVA基础要夯牢                         关注走一波💕💕  

🌈🌈​​​​​​JAVA后端技术栈                          关注走一波💕💕  

🌈🌈JAVA面试八股文​​​​​​                          关注走一波💕💕  

🌈🌈JAVA项目(含源码深度剖析)    关注走一波💕💕  

🌈🌈计算机四件套                               关注走一波💕💕  

🌈🌈数据结构与算法                           ​关注走一波💕💕  

🌈🌈必知必会工具集                           关注走一波💕💕

🌈🌈书籍网课笔记汇总                       关注走一波💕💕         



📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤收藏✅ 评论💬,大佬三连必回哦!thanks!!!
📚愿大家都能学有所得,功不唐捐!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值