欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Double-Checked Locking失效问题 博客分类: 计算机与 Internet 多线程thread框架 

程序员文章站 2024-03-17 19:12:28
...
双重检查锁定失效问题,一直是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