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 中双重检查锁定被破坏?


基础教程推荐
- 如何在 JFrame 中覆盖 windowsClosing 事件 2022-01-01
- 如何在 Spring @Value 注解中正确指定默认值? 2022-01-01
- Java Swing计时器未清除 2022-01-01
- 验证是否调用了所有 getter 方法 2022-01-01
- 在 Java 中创建日期的正确方法是什么? 2022-01-01
- 从 python 访问 JVM 2022-01-01
- 多个组件的复杂布局 2022-01-01
- Java 实例变量在两个语句中声明和初始化 2022-01-01
- 大摇大摆的枚举 2022-01-01
- 不推荐使用 Api 注释的描述 2022-01-01