双重检查锁定的由来
在Java程序中,有时需要推迟一些高开销的对象的初始化操作,并且只有在真正使用到这个对象的时候,才进行初始化,此时,就需要延迟初始化技术。
延迟初始化的正确实现是需要一些技巧的,否则容易出现问题,下面一一介绍。

方案1

public class UnsafeLazyInit{
private static Instance instance; public static Instance getInstance(){ if (instance == null){ instance = new Instance(); } return instance; }
}   

这种做法的错误是很明显的,如果两个线程分别调用getInstance,由于对共享变量的访问没有做同步,很容易出现下面两种情况:
1.线程A和B都看到instance没有初始化,于是分别进行了初始化。
2.instance=new Instance操作被重排序,实际执行过程可能是:先分配内存,然后赋值给instance,最后再执行初始化。
如果是这样的话,其他线程可能就会读取到尚未初始化完成的instance对象。

方案2

public class UnsafeLazyInit{
private static Instance instance; public static synchronized Instance getInstance(){ if (instance == null){ instance = new Instance(); } return instance; }
} 

这种做法的问题是很明显的,每一次读取instance都需要同步,可能会对性能产生较大的影响。

方案3

方案3是一个错误的双重检测加锁实现,看代码:

public class UnsafeLazyInit{
private static Instance instance; public static Instance getInstance(){ if (instance == null){ synchronized(UnsafeLazyInit.classs){ if (instance == null){ instance = new Instance(); } } } return instance; }
} 

这种方案看似解决了上面两种方案都存在的问题,但是也是有问题的。

问题根源

instance = new Instance();

这一条语句在实际执行中,可能会被拆分程三条语句,如下:

memory = allocate();
ctorInstance(memory); //2
instance = memory; //3 

根据重排序规则,后两条语句不存在数据依赖,因此是可以进行重排序的。
重排序之后,就意味着,instance域在被赋值了之后,指向的对象可能尚未初始化完成,而instance域是一个静态域,
可以被其他线程读取到,那么其他线程就可以读取到尚未初始化完成的instance域。

基于volatile的解决方案

要解决这个办法,只需要禁止语句2和语句3进行重排序即可,因此可以使用volatile来修改instance就能做到了。

private volatile static Instance instance;

因为Volatile语义会禁止编译器将volatile写之前的操作重排序到volatile之后。

基于类初始化的解决方案

Java语言规范规定,对于每一个类或者接口C ,都有一个唯一的初始化锁LC与之对应,从C到LC的映射,由JVM实现。
每个线程在读取一个类的信息时,如果此类尚未初始化,则尝试获取LC去初始化,如果获取失败则等待其他线程释放LC。
如果能获取到LC,则要判断类的初始化状态,如果是位初始化,则要进行初始化。如果是正在初始化,
则要等待其他线程初始化完成,如果是已经初始化,则直接使用此类对象。

public class InstanceFactory {private static class InstanceHolder {public static Instance instance = new Instance();}public static Instance getInstance() {return InstanceHolder.instance ;  //这里将导致InstanceHolder类被初始化
    }
}

结论

字段延迟初始化降低了初始化类或者创建实例的开销,但是增加零访问被延迟促使化的字段的开销。
在大部分时候,正常的初始化要优于延迟初始化。如果确实需要对实例字段使用线程安全的延迟初始化,
请使用上面介绍的基于volatile的延迟初始化方案;如果确实需要对静态字段使用线程安全的延迟初始化,
请使用上面基于类初始化方案的延迟初始化。

转载于:https://www.cnblogs.com/rinack/p/6066847.html

JAVA 双重检查锁定和延迟初始化相关推荐

  1. 单例-双重检查锁定与延迟初始化

    在java程序中,有时候可能需要推迟一些高开销的对象初始化操作,并且只有在使用这些对象时才进行初始化.此时程序员可能会采用延迟初始化.但要正确实现线程安全的延迟初始化需要一些技巧,否则很容易出现问题. ...

  2. java 双重检查锁定及单例模式

    双重检查锁定及单例模式 全面理解这一失效的编程习语 Peter Haggar , 高级软件工程师, IBM Peter Haggar 是 IBM 在北卡罗来纳州的 Research Triangle ...

  3. java 双重检查锁定_Java双重检查锁定

    如果initialized是这样的话会奏效volatile.就像synchronized的有趣影响volatile一样,与参考数据的关系并不像我们对其他数据的说法那么重要.在写入之前,必须进行inst ...

  4. singleton 类_在Java中对Singleton类进行双重检查锁定

    singleton 类 Singleton类在Java开发人员中非常常见,但是它给初级开发人员带来了许多挑战. 他们面临的主要挑战之一是如何使Singleton保持为Singleton? 也就是说,无 ...

  5. Java中的双重检查锁定

    在本文中,我们将介绍在RxJava中创建Singleton对象的一些技术. 最重要的是,我们将学习Java中的双重检查锁定 . Java中的Singleton模式是一种创新模式. 随着时间的流逝,人们 ...

  6. java 双重检查锁_Java中可怕的双重检查锁定习惯用法

    java 双重检查锁 本文讨论的问题不是新问题,但即使是经验丰富的开发人员也仍然很棘手. 单例模式是常见的编程习惯用法. 但是,当与多个线程一起使用时,必须进行某种类型的同步,以免破坏代码. 在相关文 ...

  7. 在Java中对Singleton类进行双重检查锁定

    Singleton类在Java开发人员中非常常见,但是它给初级开发人员带来了许多挑战. 他们面临的主要挑战之一是如何使Singleton保持为Singleton? 也就是说,无论出于何种原因,如何防止 ...

  8. Java中可怕的双重检查锁定成语

    本文讨论的问题不是新问题,但即使是经验丰富的开发人员也仍然很棘手. 单例模式是常见的编程习惯. 但是,当与多个线程一起使用时,必须进行某种类型的同步,以免破坏代码. Khangaonkar报告中的 J ...

  9. Java盲点:双重检查锁定及单例模式

    时间:2009-08-11 19:20    来源:未知    作者:Peter Haggar 核心提示:Peter Haggar , 高级软件工程师, IBM 2004 年 5 月 01 日 所有的 ...

最新文章

  1. 经典PV操作问题 [转]
  2. css 找到隐藏元素个数
  3. oracle可以注入吗,ORACLE 注入
  4. python-模块的操作-安装-导入-使用
  5. JavaScript解决e6不支持不支持max-width,max-height的问题的方法
  6. 软件就像大教堂:我们建造它们——然后祈祷
  7. hive 的drop table命令出错
  8. 周志华《机器学习》读书笔记与习题答案(持续更新)
  9. 25个深度学习开源数据集
  10. jdbc 4.0连接mysql_使用JDBC连接操作数据库
  11. 一个学习PCI Express的 不错去处
  12. 材料科学需要用计算机吗,计算机在材料科学中的运用分析
  13. 老猿学5G随笔:RAN、RAT以及anchor移动性锚点的概念
  14. php openssl 生成der,openssl asn.1 生成DER文件,把DER文件转换成内部数据结构
  15. mysql存储过程算四分位
  16. IOS 文件读写操作详解及简单实例
  17. 专注于企业元器件参数管理的物料库管理系统
  18. python + selenium + unittest 实现网站登录注册自动化测试
  19. 回归综合案例——利用回归模型预测鲍鱼年龄
  20. 获取秒懂百科视频地址/获取百度百科视频地址

热门文章

  1. app专项测试(稳定性测试、安全性测试)
  2. 一场面试,用20秒介绍自己顺便教训了领导
  3. HDU4825 Xor Sum —— Trie树
  4. 软件工程实践2017第二次作业
  5. 成都Uber优步司机奖励政策(4月8日)
  6. js 中 setInterval 的返回值问题
  7. 华为2011上机笔试题2+参考程序
  8. 《侠侣天下》资料片武魂大揭晓
  9. C#组件开发 -- 索引器
  10. 手工部署Sqlserver CLR程序集