文档章节

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

DannyCoder
 DannyCoder
发布于 07/22 14:20
字数 857
阅读 21
收藏 3

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

 

Double  Check Lock (DCL)实现单例

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

本程序的 亮点自然在getInstance方法上面,可以看到该方法对instance进行了两次判空:第一层主要是为了避免不必要的同步,第二层判断则是为了在null情况下才创建实例。这是什么意思呢?是不是有点摸不着头脑,下面就一起来分析一下。

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

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

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

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

    但是,由于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版本下使用,否则,这种方式一般能够满足要求。

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

本文转载自:https://blog.csdn.net/dgh032/article/details/80179698

共有 人打赏支持
DannyCoder
粉丝 2
博文 68
码字总数 36116
作品 0
广州
程序员
私信 提问
Java多线程学习(四)

单例模式 1.1立即加载/饿汉模式 立即加载既为使用类的方法的时候已经将对象创建完毕。常见的实现方法就是直接new实例化。 public class MyObject { private static MyObject myObject = new...

kakayang2011
2016/03/06
39
2
关于双重检测锁的一种无volatile实现

本文已同步到http://liumian.win/2016/12/17/dcl-without-volatile/ 上一篇博客中提到双重检测锁的无volatile实现,如何实现呢?那么在这篇博客中来一探究竟吧~ 无volatile的安全实现 先上代...

那只是一股逆流
2016/12/17
353
0
02、单例模式--SingleTon

单例模式大纲 版权声明:本文为博主原创文章,未经博主允许不得转载 PS:转载请注明出处 作者: TigerChain 地址: http://www.jianshu.com/p/62b2e89621a5 本文出自 TigerChain 简书 人人都会...

TigerChain
2017/11/04
0
0
说一说你对DCL双检查锁的了解?

DCL双检查锁是的初衷是为了解决实现单例对象的懒加载时,避免过度同步导致的性能开销,在获取单例的构造方法中通过两层if null的空校验进行双层检查,在最里面的一层校验外加了synchronized同...

nj-zhangmq
2016/12/09
15
0
Java五种单例模式与线程安全

懒汉式 顾名思义,lazy loading(延迟加载,一说懒加载),在需要的时候才创建单例对象,而不是随着软件系统的运行或者当类被加载器加载的时候就创建。当单例类的创建或者单例对象的存在会消...

ljrapple
2016/07/14
56
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Cloud 分布式链路跟踪 Sleuth + Zipkin + Elasticsearch

随着业务越来越复杂,系统也随之进行各种拆分,特别是随着微服务架构的兴起,看似一个简单的应用,后台可能很多服务在支撑;一个请求可能需要多个服务的调用;当请求迟缓或不可用时,无法得知...

编程SHA
11分钟前
1
0
Swift-清除缓存

func removeCache (){ // 取出cache文件夹路径.如果清除其他位子的可以将cachesDirectory换成对应的文件夹 let cachePath = NSSearchPathForDirectoriesInDomains(FileMan...

west_zll
11分钟前
1
0
kl键盘事件

frameworks/base/data/keyboards路径下定义了很对kl文件。如Vendor_0416_Product_0300.kl,定义了某某遥控器的按键事件 # TVkey 103 DPAD_UPkey 108 DPAD_DOWNkey 105 DPAD_LEFTk...

安卓工程师王恒
15分钟前
1
0
CentOS 7 安装 Docker

工具: Oracle VM VirtualBox 虚拟机 ,本地电脑win10 系统: 虚拟机装 centos 7 前置条件: Docker 要求 CentOS 系统的内核版本高于 3.10 1. 通过 uname -r 命令查看当前的内核版本 2. 如果不够...

_大侠__
25分钟前
1
0
webrtc onAddStream回调流程

背景 webrtc代码基于M59 正文 1. 回调设置和处理 (1)java层先在监听器中实现回调处理函数,如下所示: private class PCObserver implements PeerConnection.Observer { @Override...

bill_shen
27分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部