经典j2ee设计模式Double-Checked Locking失效问题

本文深入解析Java多重线程环境下双重检查锁定(DCL)失效问题,通过理解延迟加载概念,分析DCL失效的成因,并提供替代方案Initialize-On-Demand以确保线程安全。

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

双重检查锁定失效问题,一直是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(); 
             } 
          } 
        } 
        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 classLazyFoo { 
    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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值