欢迎来到代码驿站!

JAVA代码

当前位置:首页 > 软件编程 > JAVA代码

java双重检查锁定的实现代码

时间:2021-03-03 10:09:01|栏目:JAVA代码|点击:

在Java程序中,有时候可能需要推迟一些高开销的对象初始化操作,并且只有在使用这些对象时才进行初始化 。这称为延迟初始化或懒加载

    看一个不安全的延迟初始化:

A线程执行1后,发现对象instance为null,准备对其new,而B线程却先new了,这造成了错误

  我们可以利用同步锁,保证正确:

   但是对整个方法进行同步开销太大,人们想出了双重检查锁定:

最小范围所用同步锁,利用双重检查看似实现了目的,但这出现了一个问题:当A线程4执行时,线程B的7还未执行完成,而线程A判定instance != null.   线程B的7还未执行完成,为什么会出现这种情况?

   看一下new Instance()的底层关键实现:

其实是先执行1分配内存,然后再初始化对象和设置instance.然后这里存在重排,2和3的顺序可能被调换:

所以当B还执行完7时,A在4判定instance对象已经完成初始化了,如果在ctorInstance(memory)之前去调用instance就会出错。

  解决办法有两个:

1.将instance对象声明为volatile,它会禁止2,3的重排

 2.利用基于类初始化的解决方案 :JVM在类的初始化阶段(即在Class被加载后,且被线程使用之前),会执行类的初始化。在

执行类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化

  我们会发现基于类初始化的方案的实现代码更简洁。但基于volatile的双重检查锁定的方案有一个额外的优势:除了可以对静态字段实现延迟初始化外,还可以对实例字段实现延迟初始化。字段延迟初始化降低了初始化类或创建实例的开 销,但增加了访问被延迟初始化的字段的开销。在大多数时候,正常的初始化要优于延迟初始化。如果确实需要对实例字段使用线程安全的延迟初始化,请使用上面介绍的基于volatile的延迟初始化的方案;如果确实需要对静态字段使用线程安全的延迟初始化,请使用上面介绍的基于类初始化的方案。

总结

上一篇:Java操作Zookeeper原理及过程详解

栏    目:JAVA代码

下一篇:SpringBoot中的Thymeleaf模板

本文标题:java双重检查锁定的实现代码

本文地址:http://www.codeinn.net/misctech/73525.html

推荐教程

广告投放 | 联系我们 | 版权申明

重要申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:914707363 | 邮箱:codeinn#126.com(#换成@)

Copyright © 2020 代码驿站 版权所有