最近看了 Brian Goetz 写的一篇有关 DCL 的文章:Double-checked locking: Clever, but broken。(2001 年发表于 JavaWorld 上)

这篇文章讲述了 DCL 设计的初衷,但是因为 JVM 的不同实现(没有严格遵循 JMM 规范)导致 DCL 在实际应用中失效。

1. DCL 的设计初衷

DCL 是为了支持 Lazy initialization 而设计的。

我们有多种方式去实现单例模式:

  • Eager initialization: 饿加载,当类加载器加载类时就初始化类变量。这种方式可以保证初始化的原子性,但降低了程序的启动性能(类加载过程中的初始化阶段对类变量初始化)。
  • Lazy initialization: 懒加载,当需要使用类变量时才进行初始化。这种方式可以提高程序的启动性能,但需要同步来保证初始化的原子性,无疑带来了同步开销。

DCL 的目标是(1)提高程序的启动性能,(2)降低同步开销。

代码示例:

  1. class SomeClass {
  2. private Resource resource = null;
  3. public Resource getResource() {
  4. if (resource == null)
  5. resource = new Resource();
  6. return resource;
  7. }
  8. }

2. DCL 失效的原因

DCL 要真正有效,需要依赖 JVM 真正遵循了 JMM 规范。

实际中,编译器、处理器、缓存都可以“自由”执行代码(乱序执行),只要保证 as-if-serial semantics 就行。

这里要提及 synchronized 的作用:

  • 互斥执行某段代码
  • 触发 memory barrier ,强制线程的工作内存与住内存同步

适当地使用同步可以保证:一个线程预期地看到另一个线程的影响(The proper synchronization guarantees that one thread will see the effects of another in a predictable manner)。

DCL 之所以失效,是因为没有同步地使用 resource。(与上文提到的乱序执行有关,这个与具体的 JVM 版本有关,很多 JVM 实现没有严格实现JMM规范)

3. 解决方案

(1)不使用 DCL;

(2)使用饿加载(Eager initialization),由类加载器保证类变量初始化的互斥性(每个类只会加载一次);

(3)懒加载有个特例:只含有一个类变量,不含类方法、实例变量、实例方法;

(4)对 32bit primitive values 有效。

DCL的失效:现实与初衷的背离的更多相关文章

  1. Design Patterns in Android

    对日常在 Android 中实用设计模式进行一下梳理和总结,文中参考了一些网站和大佬的博客,如 MichaelX(xiong_it) .菜鸟教程.四月葡萄.IAM四十二等,在这里注明下~另外强烈推荐图 ...

  2. Android经典的设计模式

    [单例模式][Build模式][原型模式][工厂模式][策略模式][状态模式][责任链模式][解释器模式][命令模式][观察者模式][备忘录模式][迭代器模式] [模板方法模式][访问者模式][中介者 ...

  3. Android中的创建型模式总结

    共5种,单例模式.工厂方法模式.抽象工厂模式.建造者模式.原型模式 单例模式 定义:确保某一个类的实例只有一个,而且向其他类提供这个实例. 单例模式的使用场景:某个类的创建需要消耗大量资源,new一个 ...

  4. python的高级应用

    记录一下Python函数式编程,高级的几个BIF,高级官方库方面的用法和心得. 函数式编程 函数式编程是使用一系列函数去解决问题,按照一般编程思维,面对问题时我们的思考方式是"怎么干&quo ...

  5. SQL SERVER 中is null 和 is not null 将会导致索引失效吗?

    其实本来这个问题没有什么好说的,今天优化的时候遇到一个SQL语句,因为比较有意思,所以我截取.简化了SQL语句,演示给大家看,如下所示 declare @bamboo_Code varchar(3); ...

  6. ddl dml dcl

    DCL数据控制语言 创建临时表空间 create temporary tablespace user_temp tempfile 'E:/oracle/product/10.1.0/oradata/o ...

  7. 用happen-before规则重新审视DCL(转)

    编写Java多线程程序一直以来都是一件十分困难的事,多线程程序的bug很难测试,DCL(Double Check Lock)就是一个典型,因此对多线程安全的理论分析就显得十分重要,当然这决不是说对多线 ...

  8. DCL,DDL,DML,DQL

    DCL(Data Control Language)是数据库控制语言. 是用来设置或更改数据库用户或角色权限的语句,包括(grant,deny,revoke等)语句. 在默认状态下,只有sysadmi ...

  9. DML,DDL,DCL,DQL的区别

      DML 英文缩写 DML = Data Manipulation Language,数据操纵语言,命令使用户能够查询数据库以及操作已有数据库中的数据的计算机语言.具体是指是UPDATE更新.INS ...

随机推荐

  1. java基础回顾(一)

    java的特点:开源.安全.跨平台.简单易懂.一次编译可多处运行. JDK:java开发工具包 JDK = JRE+JAVA开发工具 保证能够实现java开发的最小单元 JRE:java运行环境 JR ...

  2. Servlet之过滤器(Filter)和监听器(Listener)

    过滤器 过滤器是一个java组件,可以拦截发送至某个servelet,jsp页面或静态页面的请求,可以在响应发送到客户之前进行拦截 工作原理: 过滤器类必须实现 Filter 接口,包含的方法如下: ...

  3. C++PRIMER 阅读笔记 第三章

    本章主要介绍 string vector 和 bitset, 不能贪多,现在本文主要介绍 string 与 vector 头文件中最好不要使用namespace std, 因为头文件会直接被预处理器放 ...

  4. 2017最新PHP经典面试题目汇总(上篇)

    1.双引号和单引号的区别 双引号解释变量,单引号不解释变量 双引号里插入单引号,其中单引号里如果有变量的话,变量解释 双引号的变量名后面必须要有一个非数字.字母.下划线的特殊字符,或者用{}讲变量括起 ...

  5. mysql复习秘籍

    mysql复习 一:复习前的准备 1:确认你已安装wamp 2:确认你已安装ecshop,并且ecshop的数据库名为shop 二 基础知识: 1.数据库的连接 mysql -u -p -h -u 用 ...

  6. python :ascii codec can't decode byte 0xe8 in posit

    python代码: slide.setAttribute("SlideName", module.slide_name)  slide.setAttribute("Sli ...

  7. django同时查询两张表的数据,合并检索对象返回

    原始需求: 1.一篇文章内容分N个版块,每篇文章的版块数量不同. 2.有个文章搜索功能,需要同时搜索标题和内容. 实现思路: 1.由于每篇文章的内容版块数量不同,因此将每个文章的标题和内容分开存入2张 ...

  8. ajax请求处理和views处理函数的优先级

    当采用ajax处理请求的时候,在views函数中使用 return render(request,'XXX.html',{'error':form.get_error()}) 返回渲染模板时,会优先处 ...

  9. 一行代码搞定ThoughtWorks面试题

    今天在微博看到一道有趣的题目.作为python的脑残粉,自然手痒. 题目在这里. FizzBuzzWhizz 你是一名体育老师.在某次课距离下课还有五分钟时,你决定搞一个游戏.此时有100名学生在上课 ...

  10. R语言与数据分析之八:时间序列--霍尔特指数平滑法

    上篇我和小伙伴们分享了简单指数平滑法,简单指数平滑法仅仅能预測那些处于恒定水平和没有季节变动的时间序列,今天和大家分享非恒定水平即有增长或者减少趋势的.没有季节性可相加模型的时间序列预測算法---霍尔 ...