背景&问题

在早期的JVM中,synchronized存在巨大的性能开销。因此,有人想出了一个“聪明”的技巧:双重检查锁定(Double-Checked Locking)。人们想通过双重检查锁定来降低同步的开销。下面是使用双重检查锁定来实现延迟初始化的示例代码。

public class DoubleCheckedLocking { // 1
private static Instance instance; // 2
public static Instance getInstance() { // 3
if (instance == null) { // 4:第一次检查
synchronized (DoubleCheckedLocking.class) { // 5:加锁
if (instance == null) // 6:第二次检查
instance = new Instance(); // 7:问题的根源出在这里
} // 8
} // 9
return instance; // 10
} // 11
}

上述的Instance类变量是没有用volatile关键字修饰的,会导致这样一个问题:

在线程执行到第4行的时候,代码读取到instance不为null时,instance引用的对象有可能还没有完成初始化。

原因

主要的原因是重排序。重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。

第7行的代码创建了一个对象,这一行代码可以分解成3个操作:

memory = allocate();  // 1:分配对象的内存空间
ctorInstance(memory); // 2:初始化对象
instance = memory;  // 3:设置instance指向刚分配的内存地址

根源在于代码中的2和3之间,可能会被重排序。例如:

memory = allocate();  // 1:分配对象的内存空间
instance = memory;  // 3:设置instance指向刚分配的内存地址
// 注意,此时对象还没有被初始化!
ctorInstance(memory); // 2:初始化对象java

这在单线程环境下是没有问题的,但在多线程环境下会出现问题:B线程会看到一个还没有被初始化的对象。

A2和A3的重排序不影响线程A的最终结果,但会导致线程B在B1处判断出instance不为空,线程B接下来将访问instance引用的对象。此时,线程B将会访问到一个还未初始化的对象。

改进

所以只需要做一点小的修改(把instance声明为volatile型),就可以实现线程安全的延迟初始化。因为被volatile关键字修饰的变量是被禁止重排序的。

最新文章

  1. socket编程基础
  2. onBackPressed
  3. 4.openstack之mitaka搭建glance镜像服务
  4. JDK AIO编程
  5. java.io.IOException: Too many open files
  6. CSS3常用选择器(二)
  7. 20135316王剑桥 linux第十二周课实验笔记
  8. hdu 3007 Buried memory 最远点对
  9. centos 服务器配置(一) 之端口占用
  10. IDEA 编译错误:java: try-with-resources is not supported in -source 1.6 (use -source 7 or higher to enable try-with-resources)
  11. WPF 皮肤之MathApps.Metro UI库
  12. ACM——大数相加
  13. nav标签的作用
  14. 利用EntityFramework获得双色球数据库
  15. 【BZOJ2054】疯狂的馒头(并查集)
  16. Dom4j 封装DOM和SAX 的方法
  17. Jenkins2.32打包Unity项目的记录
  18. release 步骤
  19. 列表 list 容器类型数据(str字符串, list列表, tuple元组, set集合, dict字典)--->元组 tuple-->字符串 str
  20. 使用Git上传代码到Github仓库

热门文章

  1. 小程序开发--API之登录授权逻辑
  2. windows2008服务器设置系统启动时程序自动运行
  3. ROUND() 函数
  4. java基础类型源码解析之String
  5. JavaWeb基础知识
  6. Python_BDD概念
  7. 分享CSS3里box-shadow属性的使用方法,包括内阴影box-shadow:inset
  8. List三个子类的特点
  9. i18n 语言码和对应的语言库
  10. React之简介