java - 为什么在单例类的情况下双重检查锁定不会像这样失败?

标签 java multithreading singleton synchronized double-checked-locking

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/

相关文章:

java - 如何保证事务服务方法中的行级唯一约束?

C#多线程文件IO(阅读)

c++ - Generic Singleton Wrapper类的设计

java - 实用程序库的日志记录标准

java - 玩! Framework 2.5 如何在异步回调中返回 delegate.call(ctx)

c++ - 管理异步通信: how to examine response received in another thread

C++11 线程 : Exception when called using lambdas

ios - 用户信息。是否使用单例类?

java - 单例模式 "Access to Constructor not Allowed"

java - Hibernate\JPA 在高并发 Web 应用程序上的使用