`

Double-Checked Locking失效问题

阅读更多
双重检查锁定失效问题,一直是JMM无法避免的缺陷之一.了解DCL失效问题, 可以帮助我们深入JMM运行原理.
要展示DCL失效问题, 首先要理解一个重要概念- 延迟加载(lazy loading).

非单例的单线程延迟加载示例:
class Foo {
    private Resource res = null;
    public Resource getResource() {
        //普通的延迟加载
        if (res == null)
            res = new Resource();
        return res;
    }
}

非单例的
多线程延迟加载示例:
Class Foo {
    private Resource res = null;
    public synchronized Resource getResource() {
        //获取实例操作使用同步方式, 性能不高
        if (res == null)
            res = new Resource();
        return res;
    }
}

非单例的
DCL多线程延迟加载示例:
Class Foo {
    private Resource res = null;
    public Resource getResource() {
        if (res == null) {
            //只有在第一次初始化时,才使用同步方式.
            synchronized(this) {
                if(res == null) {
                    res = new Resource();
                }
            }
        } // end if null
        return res;
    } 
}

Double-Checked Locking看起来是非常完美的。但是很遗憾,根据Java的语言规范,上面的代码是不可靠的。

出现上述问题, 最重要的2个原因如下:
1, 编译器优化了程序指令, 以加快cpu处理速度.
2, 多核cpu动态调整指令顺序, 以加快并行运算能力.

问题出现的顺序:
1, 线程A, 发现对象未实例化, 准备开始实例化
2, 由于编译器优化了程序指令, 允许对象在构造函数未调用完前, 将
共享变量的引用指向
部分构造的对象, 虽然对象未完全实例化, 但已经不为null了.
3, 线程B, 发现部分构造的对象已不是null, 则直接返回了该对象.

不过, 一些著名的开源框架, 包括jive,lenya等也都在使用DCL模式, 且未见一些极端异常.
说明, DCL失效问题的出现率还是比较低的.
接下来就是性能与稳定之间的选择了?

DCL的替代
Initialize-On-Demand
:

public class Foo {
    // 私有静态内部类, 只有当有引用时, 该类才会被装载
    private static class LazyFoo {
       public static Foo foo = new Foo();
    }

    public static Foo getInstance() {
       return LazyFoo.foo;
    }
}


维基百科的DCL解释:
http://en.wikipedia.org/wiki/Double-checked_locking
DCL的完美解决方案:
http://www.theserverside.com/patterns/thread.tss?thread_id=39606
分享到:
评论

相关推荐

    C++ and the Perils of Double-Checked Locking

    在介绍双检锁模式(Double-Checked Locking Pattern,DCLP)的C++实现中,Scott Meyers和Andrei Alexandrescu在其2004年的文章中指出,传统的单例模式实现并不具备线程安全性。单例模式是设计模式中经常被提及的一种...

    JAVA内存模型

    Double-Checked Locking(DCL)是一种常用于延迟初始化的优化技术,其核心思想是在第一次检查实例是否为空之后,再使用`synchronized`关键字进行第二次检查。然而,DCL模式在JMM中可能会失效。 ##### DCL失效案例...

    java之 ------ 几种常见的简单设计模式

    - 可以通过双重检查锁定(Double-Checked Locking)优化性能。 **线程安全问题及解决方案** - **问题**:在多线程环境中,若不采取措施,则可能会导致单例模式失效,即生成多个实例。 - **解决方案**: - 使用`...

    阿里druid数据库连接池

    Druid通过优化内部实现,如使用双重检查锁定(double-checked locking)避免并发问题,以及使用直接内存分配提升数据传输速度,实现了比DBCP和C3P0更高的性能。同时,Druid的连接池管理算法也更加智能,能有效避免...

    Java线程内存模型的缺陷.docx

    #### DCL(Double-Checked Locking)失效 DCL是一种常见的懒加载模式,旨在减少不必要的同步开销。然而,在Java中,DCL模式可能存在缺陷,尤其是在早期的JVM版本中。 ##### DCL的基本原理 DCL模式通常采用以下...

    单态模式的设计和应用

    懒汉式的一个改进是**双重检查锁定(Double-Checked Locking, DCL)**,它尝试减少不必要的同步开销: ```java public class Singleton { private volatile static Singleton instance = null; private Singleton...

    activity service broadcast 单例模式 的综合使用

    为确保线程安全,通常使用双检锁/双重校验锁(DCL,即double-checked locking)或者静态内部类来实现。 5. **组件间的通信**:Activity和服务之间可以通过Intent进行通信,服务可以通过startActivityForResult()...

    Redis非关系型数据库笔记-数据持久化-主从同步-缓存-笔记-五大数据类型-三大特殊数据类型

    - **解决方案**: 使用互斥锁(Mutex)或者双重检查锁定(Double-Checked Locking)来控制并发访问。 - **缓存雪崩**: 缓存中大量数据同时失效,导致所有请求都落到后端数据库。 - **解决方案**: 分布式缓存失效策略,...

    单例模式七种写法_转

    文章提到的双重检查锁定(Double-Checked Locking,简称DCL)是一个在单例模式中用来优化性能的编程技巧。该技巧的核心在于减少同步的开销,在多线程环境下,仅在实例未被创建时才同步。然而,这个技巧在Java早期...

    Java设计模式之单态模式(Singleton模式)介绍

    为了解决这个问题,可以使用双重检查锁定(Double-Checked Locking,DCL)优化懒汉式,但这需要依赖于Java内存模型(JMM)来保证正确性,如下所示: ```java public class Singleton { private volatile static ...

    简单了解java volatile关键字实现的原理

    2. **双重检查锁定**:在单例模式中,`volatile`结合双重检查锁定(Double-Checked Locking)可以保证线程安全地创建单例。首先检查实例是否已创建,如果未创建,才进行同步创建,`volatile`确保在多个线程中只实例...

    用于App服务端的MySQL连接池(支持高并发)

    单例模式通过双重检查锁定(double-checked locking)来实现,这既保证了线程安全,又避免了不必要的同步开销。 在`MySQLPool`类中,`MysqlDataSource` 是连接池的基础,它是JDBC的MySQL数据源实现,提供了配置...

    单例模式,single

    例如,懒汉式单例模式中,可以在 `getInstance()` 方法上添加 `synchronized` 关键字,或者采用双重检查锁定(Double Checked Locking)模式。 2. **类加载器问题的解决**:为了解决不同类加载器加载同一个类产生的...

Global site tag (gtag.js) - Google Analytics