这个代码Double Checked Locking安全吗?

时间:2011-12-06 22:58:24

标签: java multithreading concurrency double-checked-locking

我正在查看我们的应用中的一些代码,我认为可能会遇到“Double-checked locking”的情况。我编写了一些类似于我们的示例代码。

任何人都可以看到这是如何经历双重检查锁定的吗?或者这样安全吗?

class Foo {
    private Helper helper = null;
    public Helper getHelper() {
        Helper result;
        synchronized(this) {
            result = helper;
        }

        if (helper == null) {
            synchronized(this) {
                if (helper == null) {
                    helper = new Helper();
                }
            }
        }
        return helper;
    }
}

wiki借来的基本代码。

3 个答案:

答案 0 :(得分:6)

这是不必要的复杂,最简单的“安全”做DCL的方式是这样的:

class Foo {
  private volatile Helper helper = null;
  private final Object mutex = new Object(); 
  public Helper getHelper() {
    if (helper == null) {
        synchronized(mutex) {
            if (helper == null) {
                helper = new Helper();
            }
        }
    }
    return helper;
  }
}

这里的关键点是:

  • 在'happy'的情况下,我们希望已经分配了helper,所以如果是,我们可以返回它而不必输入synchronized块。
  • Helper被标记为volatile,让编译器知道任何线程都可以随时读取/写入帮助程序,读取/写入不重新排序很重要。
  • synchronized块使用私有final变量进行同步,以避免在this实例上另一个代码区域同步的情况下可能出现性能损失。

答案 1 :(得分:3)

双重检查锁定的重点是快速路径(当您不需要实例化对象时)不同步。所以你所拥有的不是双重锁定。

你需要摆脱第一个同步的块,以获得一个破坏的双重检查锁。然后你需要让helper volatile来修复它。

答案 2 :(得分:0)

这部分是标准的双重检查锁定:

if (helper == null) {
    synchronized(this) {
        if (helper == null) {
            helper = new Helper();
        }
    }
}

第一部分是无用的赋值,它对双重检查的锁定部分没有任何作用:如果helper为null则无论如何都会执行,如果不是,则无论如何都不会执行。它完全无效。