糟糕的双重检查加锁(DCL)
在Java并发编程时,同步都会存在着巨大的性能开销,因此,人们使用了很多的技巧来降低同步的影响,这其中有一些技巧很好,但是也有一些技巧存在一些缺陷,下面要结束的双重检查加锁(DCL)就是有缺陷的一类。
由于早期的JVM在性能上存在一些有待优化的地方,因此在并发编程中,延迟初始化经常被用来降低程序的开销。编写正确的延迟初始化需要使用同步,但是直接在初始化之前使用同步会对性能产生影响。所以一些人就提出了双重检查加锁,并声称能够解决这个矛盾。如图所示就是双重检查加锁的代码。

上图代码中,对Resource资源进行延时初始化,在初始化之前需要判断资源是否已经初始化过,所以进行了第一次没有同步的非空判断,resource对象却是为空时,再来对resource对象进行初始化,并将这部分初始化的代码加了类锁进行同步。这代码咋一看确实非常好,首先在第一次非空判断的时候,没有进行同步,只要对象完成了初始化,那么代码就永远走不到同步块中,所以不会有性能问题。但是仔细分析之后,其实是有缺陷的。
这段代码的缺陷就是线程有可能会使用一个仅被部分构造的Resource对象。双重检查加锁的问题在于,当在没有同步的情况下读取一个共享对象的时候,最坏的情况下,有可能得到的是一个失效的值。这是由于我们在判断对象是否完成初始化是,只是判断对象的引用是否非空,然后在初始化对象时,JVM会在堆上给对象分配一块内存,然后JVM会干两件事,将内存的地址作为引用分配给变量和在堆上初始化这个对象,但是这两件事的先后顺序是不确定的,因此有可能resource非空,但是对象并没有初始化完成。
所以在实际编程中一定要注意尽量不要使用双重检查加锁,如果一定要使用,那么可以将resource声明为volatile类型,这种方式对性能的影响是很小的,并且还能保证每个线程都能获取到最新的对象。
糟糕的双重检查加锁(DCL)的更多相关文章
- 单例---被废弃的DCL双重检查加锁
被废弃的单例的DCL双重检查加锁/* *单例模式 *单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点. *加同步锁的单例模式,适合在多线程中使用. */ class Singleton{ ...
- 【线程安全】—— 单例类双重检查加锁(double-checked locking)
1. 三个版本单例类的实现 版本1:经典版 public class Singleton { public static Singleton getInstance() { if (instance ...
- 双重检查加锁机制(并发insert情况下数据重复插入问题的解决方案)
双重检查加锁机制(并发insert情况下数据重复插入问题的解决方案) c#中单例模式和双重检查锁 转:https://blog.csdn.net/zhongliangtang/article/deta ...
- 单例模式的两种实现方式对比:DCL (double check idiom)双重检查 和 lazy initialization holder class(静态内部类)
首先这两种方式都是延迟初始化机制,就是当要用到的时候再去初始化. 但是Effective Java书中说过:除非绝对必要,否则就不要这么做. 1. DCL (double checked lockin ...
- DCL,即Double Check Lock,中卫双重检查锁定。
DCL,即Double Check Lock,中卫双重检查锁定. [Java并发编程]之十六:深入Java内存模型——happen-before规则及其对DCL的分析(含代码) 关于单例.关于DCL: ...
- Java并发(七):双重检验锁定DCL
双重检查锁定(Double Check Lock,DCL) 1.懒汉式单例模式,无法保证线程安全: public class Singleton { private static Singleton ...
- 双重检查锁定与延迟初始化(转自infoq)
很好的文章,转自http://www.infoq.com/cn/articles/double-checked-locking-with-delay-initialization 在java程序中,有 ...
- Java中的双重检查锁(double checked locking)
最初的代码 在最近的项目中,写出了这样的一段代码 private static SomeClass instance; public SomeClass getInstance() { if (nul ...
- volatile双重检查锁定与延迟初始化
一.基本概念: 1.volatile是轻量级的synchronized,在多核处理器开发中保证了共享变量的“可见性”.可见性的意思是,当一个线程修改一个共享变量时,另一个线程能读到这个修改的值. 2. ...
随机推荐
- BZOJ 3166 Alo
处理出每个数最靠近它的左右两个比它大的数. 然后可持久化trie. #include<iostream> #include<cstdio> #include<cstrin ...
- 原创:js代码, 让dedecms支持Tag选择, 添加内容更为方便,不用手输Tag
dedecms在编辑修改内容时,TAG标签需要手动输,中文的Tag, 中间还得用半角字符','分隔, 输入法切来切去很不方便, 于是动手改后台代码, 利用后台的tags_main.php, 让d ...
- OK - A byte of python - 读书笔记
看这本书的目的:再熟悉基本概念. 大部分都是知道,但是需要 明确 出来的 概念. - 欢迎吐槽错误,非常感谢. <A byte of python> - THIS 1. 组织行 - 形式: ...
- Buffer cache 的调整与优化
Buffer cache 的调整与优化 -============================== -- Buffer cache 的调整与优化(一) --==================== ...
- ORACLE远程连接数据库
1. sqlplus sqlnet.ora 文件格式NAMES.DIRECTORY_PATH= (TNSNAMES,HOSTNAME).客户端就会首先在tnsnames.ora文件中找orcl的记录. ...
- 30种oracle常见的等待事件说明
1Buffer busy waits从本质上讲,这个等待事件的产生仅说明了一个会话在等待一个Buffer(数据块),但是导致这个现象的原因却有很多种.常见的两种是: 当一个会话视图修改一个数据块,但这 ...
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)宏的运行机理:1. ( (TYPE *)0 ) 将零转型为TY ...
- mysql DDL语句
sql语言分为三个级别. 1.ddl 语句 ,数据定义语句,定义了数据库.表.索引等对象的定义.常用语句包含:create.drop.alter. 2.dml 语句 ,数据操纵语句,用于添加.删除.更 ...
- 【转】javascript-图片预加载技术
1,脚本代码: /** * 图片头数据加载就绪事件 - 更快获取图片尺寸 * @version 2011.05.27 * @author TangBin * @see http://www.plane ...
- 【和我一起学python吧】Python解释执行原理
这里的解释执行是相对于编译执行而言的.我们都知道,使用C/C++之类的编译性语言编写的程序,是需要从源文件转换成计算机使用的机器语言,经过链接器链接之后形成了二进制的可执行文件.运行该程序的时候,就可 ...