3

使用双重检查锁定模式时有一个众所周知的陷阱(示例和解释摘自“实践中的并发”):

@NotThreadSafe
public class DoubleCheckedLocking {

private static Resource resource;

public static Resource getInstance() {
 if (resource == null) {
  synchronized (DoubleCheckedLocking.class) {
  if (resource == null)
    resource = new Resource();
  }
 }
 return resource;
}

}

某些线程可能会看到“资源”变量的初始化值,而对象本身仍在构建中。

一个问题是:如果我们以某种方法构造资源对象,问题是否仍然存在?IE

resource = createResource();

当资源对象仍在 createResource() 方法中构建时,某些线程可以将资源 != null 评估为 true 吗?

4

2 回答 2

3

是的,一些线程可以,或者更确切地说可以。这些天您发布的代码可以正常工作。只有在较早的内存模型(Java 1.5 之前)中,DCL 模式才存在缺陷。

现在 DCL 也已经过时了,因为创建延迟加载单例的最佳方法是使用单例枚举模式。

于 2014-08-14T19:51:54.203 回答
0

为了回答您的问题,在您给出的示例中,如果您使用方法或直接调用,行为不会改变new。影响线程之间行为的是某种类型的内存屏障。一个方法分派是不够的。

然而,双重检查锁定从 Java 5 开始工作,尽管您需要volatile在实例上使用关键字 on。(碰巧提供内存屏障。)

为什么在这个双重检查锁定示例中使用 volatile

于 2014-08-15T08:04:28.540 回答