关于DCL双重锁失效及解决方案

关于DCL双重锁失效及解决方案

 

Double  Check Lock (DCL)实现单例设计模式

DCL 方式实现单例的优势是既可以在须要时才初始化单例,又可以保证线程安全,且单例对象初始化后调用getInstance方法不进行同步锁。代码以下:安全

本程序的 亮点天然在getInstance方法上面,能够看到该方法对instance进行了两次判空:第一层主要是为了不没必要要的同步,第二层判断则是为了在null状况下才建立实例。这是什么意思呢?是否是有点摸不着头脑,下面就一块儿来分析一下。并发

假设线程A执行到singleton03  = new Singleton03()语句,看起来只有一行代码,但实际上它并非原子操做,这句代码最终会被编译成多条汇编指令,它大体作了3件事:函数

1)给singleton03的实例分配内存。高并发

2)调用Singleton03()构造函数,初始化成员字段。性能

3)将singleton03对象指向分配的内存空间(此时singleton03就不是null了)。spa

    可是,因为Java编译器容许处理器乱序执行,以及JDK1.5以前JMM中的Cache、寄存器到主内存回写顺序的规定,上面的2和3的顺序是没法保证的,也就是说,执行顺序多是1-2-3也多是1-3-2。若是是后者,而且在3执行完毕、2未执行以前,被切换到线程B上,这时候singleton03由于已经在线程A内执行过了3,singleton03已是非空了,因此,线程B直接取走singleton03,再使用时就会出错,这就是DCL失效问题,并且这种难以跟踪难以重现的错误可能会隐藏好久。线程

    在JDK1.5以后,SUN官方已经注意到这种问题,调整了JVM,具体化了volatile关键字,所以,若是JDK1.5或以后的版本,只须要将singleton03的定义改为private volatile static Singleton03 singleton = null就能够保证singleton03对象每次都是从主内存中读取,就可使用DCL的写法来完成单例模式。固然,volatile或多或少也会影响到性能,但考虑到程序的正确性,这点牺牲也是值得的。设计

    DCL优势:资源利用率高,第一次执行getInstance时单例对象才会被实例化,效率高。缺点:第一次加载稍慢,也因为JMM的缘由致使偶尔会失败。在高并发环境下也有必定的缺陷,虽然发送几率很小。DCL模式是使用最多的单例实现方式,它可以在须要时才实例化对象,而且能在绝大多数场景下保证对象的惟一性,除非你的代码在并发场景比较复杂或低于JDK1.6版本下使用,不然,这种方式通常可以知足要求。对象

以上参考《源码设计模式解析与实战》之单例模式,记以温习,如有不足,请多指教

相关文章
相关标签/搜索