这个问题与旧 Java 版本的行为和双重检查锁定算法的旧实现有关
较新的实现 use volatile
并依赖于略微改变的 volatile
语义,因此它们不会损坏。
声明字段分配始终是原子的,除了 long 或 double 字段。
但是,当我读到为什么 double-check locking 被破坏的解释时,它说问题出在赋值操作中:
// 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).
什么时候可以? 64 位 JVM 赋值操作是否可能不是原子的? 如果不是那么“双重检查锁定”是否真的被破坏了?
最佳答案
问题不在于原子性,而在于顺序。允许 JVM 重新排序指令以提高性能,只要 happens-before没有被侵犯。因此,运行时理论上可以在类 Helper
的构造函数执行完所有指令之前安排更新 helper
的指令。
关于java - 为什么在 Java 中双重检查锁定被破坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4926681/