为什么在 Java 中双重检查锁定被破坏了?
2022-09-03 12:46:27
这个问题与旧Java版本的行为和双重检查锁定算法的旧实现有关
较新的实现使用易失性
,并依赖于稍微改变的语义,因此它们不会被破坏。volatile
它指出,字段赋值始终是原子的,除了长字段或双精度字段。
但是,当我读到为什么双重检查锁定被破坏的解释时,据说问题出在分配操作中:
// 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...
}
- 线程 A 注意到该值未初始化,因此它获取锁并开始初始化该值。
- 由于某些编程语言的语义,允许编译器生成的代码在 A 完成执行初始化之前更新共享变量以指向部分构造的对象。
- 线程 B 注意到共享变量已初始化(或显示如此),并返回其值。由于线程 B 认为该值已初始化,因此它不会获取锁。如果 B 在 B 看到 A 完成的所有初始化之前使用该对象(因为 A 尚未完成初始化它,或者因为对象中的某些初始化值尚未渗透到 B 使用的内存(缓存一致性)),则程序可能会崩溃。
(来自 http://en.wikipedia.org/wiki/Double-checked_locking)。
什么时候可能?是否有可能在 64 位 JVM 上分配操作不是原子的?如果不是,那么“双重检查锁定”是否真的坏了?