1. class Foo {
2. private Helper helper = null;
3. public Helper getHelper() {
4. if (helper == null) {
5. synchronized(this) {
6. if (helper == null) {
7. helper = new Helper();
8. }
9. }
10. }
11. return helper;
12. }
13. }
此结构被视为已损坏的原因通常描述了编译器完成的赋值重新排序,以便在写入辅助变量后调用辅助构造函数。我的问题是这段代码如何保证线程安全以及是否可以执行以下步骤?
- 线程1,进入synchronized block ,发现helper为null。
- 线程1,此时放弃监听
- 线程2,进入object monitor并实例化helper
- 线程 1,返回并重新初始化 helper 实例为
我看不出这个解决方案比单一检查锁定有什么好。
最佳答案
这适用于对助手的引用,但仍然有细微的问题。
它坏了是因为 VM 可以根据需要在同步块(synchronized block)内重新排序程序操作,所以引用 helper 可以设置为非空 < em>before helper 实例(由线程 1)的构造已完成。
线程 2 现在可以在同步块(synchronized block)外看到 not-null,从不尝试进入同步块(synchronized block)(线程 1 仍持有锁并忙于构建 Helper)并使用半构建的 Helper 实例。
这可能会也可能不会发生在特定的 VM 版本上。但是规范明确允许 VM 执行此操作。这就是为什么这个例子被打破了。它可以通过声明 helper volatile 来修复(仅适用于 Java 5+)。
关于java - 为什么在单例类的情况下双重检查锁定不会像这样失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24810802/