Why is double-checked locking broken in Java?(为什么在 Java 中双重检查锁定被破坏?)
问题描述
这个问题与旧 Java 版本的行为和双重检查锁定算法的旧实现有关
较新的实现使用volatile
并依赖于稍微改变的 volatile
语义,因此它们没有损坏.
声明字段分配始终是原子的,除了 long 或 double 字段.
但是,当我读到为什么双重检查锁定被破坏的解释时,据说问题在于赋值操作:
//损坏的多线程版本//双重检查锁定"成语类Foo {私人助手 helper = null;公共助手 getHelper() {如果(助手 == null){同步(这个){如果(助手 == null){助手 = 新助手();}}}返回助手;}//其他函数和成员...}
<块引用>
- 线程 A 注意到该值没有被初始化,所以它获取了锁定并开始初始化价值.
- 由于某些编程语言的语义,代码允许编译器生成更新共享变量指向到一个部分构造的对象在 A 完成执行之前初始化.
- 线程 B 注意到共享变量已被初始化(或它出现),并返回其值.因为线程 B 认为值是已经初始化,它没有获取锁.如果 B 使用对象在所有初始化完成之前A 被 B 看到(或者因为 A尚未完成初始化或因为一些初始化值在物体中尚未渗出到内存 B 使用(缓存连贯性)),该程序可能碰撞.
(来自 http://en.wikipedia.org/wiki/Double-checked_locking).
什么时候可以?64位JVM分配操作是否可能不是原子的?如果不是,那么双重检查锁定"是否真的被破坏了?
问题不在于原子性,而在于顺序.JVM 可以重新排序指令以提高性能,只要 happens-before 没有被违反.因此,运行时理论上可以在类 Helper
的构造函数的所有指令执行之前调度更新 helper
的指令.
This question relates to behaviour of old Java versions and old implementations of the double checked locking algorithm
Newer implementations use volatile
and rely on slightly changed volatile
semantics, so they are not broken.
It's stated that fields assignment is always atomic except for fields of long or double.
But, when I read an explaination of why double-check locking is broken, it's said that the problem is in assignment operation:
// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
// other functions and members...
}
- Thread A notices that the value is not initialized, so it obtains the lock and begins to initialize the value.
- Due to the semantics of some programming languages, the code generated by the compiler is allowed to update the shared variable to point to a partially constructed object before A has finished performing the initialization.
- Thread B notices that the shared variable has been initialized (or so it appears), and returns its value. Because thread B believes the value is already initialized, it does not acquire the lock. If B uses the object before all of the initialization done by A is seen by B (either because A has not finished initializing it or because some of the initialized values in the object have not yet percolated to the memory B uses (cache coherence)), the program will likely crash.
(from http://en.wikipedia.org/wiki/Double-checked_locking).
When is it possible? Is it possible that on 64-bit JVM assignment operation isn't atomic? If no then whether "double-checked locking" is really broken?
The problem is not atomicity, it's ordering. The JVM is allowed to reorder instructions in order to improve performance, as long as happens-before is not violated. Therefore, the runtime could theoretically schedule the instruction that updates helper
before all instructions from the constructor of class Helper
have executed.
这篇关于为什么在 Java 中双重检查锁定被破坏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:为什么在 Java 中双重检查锁定被破坏?
基础教程推荐
- Java 中保存最后 N 个元素的大小受限队列 2022-01-01
- 首次使用 Hadoop,MapReduce Job 不运行 Reduce Phase 2022-01-01
- 如何对 HashSet 进行排序? 2022-01-01
- 如何强制对超级方法进行多态调用? 2022-01-01
- 由于对所需库 rt.jar 的限制,对类的访问限制? 2022-01-01
- 如何使用 Stream 在集合中拆分奇数和偶数以及两者的总和 2022-01-01
- 如何使用 Eclipse 检查调试符号状态? 2022-01-01
- 如何在不安装整个 WTP 包的情况下将 Tomcat 8 添加到 Eclipse Kepler 2022-01-01
- Spring Boot Freemarker从2.2.0升级失败 2022-01-01
- 在螺旋中写一个字符串 2022-01-01