这段代码是否解决了Java中的双重检查锁定问题?

public class DBAccessService() {
    private static DBAccessService INSTANCE;  

    private DBAccessService() {}

    public static DBAccessService getInstance() {
        if (INSTANCE != null) {
            return INSTANCE;
        }
        return createInstance();
    }

    private static synchronized DBAccessService createInstance() {
        if (INSTANCE != null) {
            return INSTANCE;
        }
        DBAccessService instance = new DBAccessService();
        INSTANCE = instance;

        return INSTANCE;
    }
}

有2个方面需要注意:

  1. getInstance()不是 同步,因此实例初始化后没有同步成本
  2. createInstance() 已同步

所以,问题是:这段代码有什么问题吗?是否合法并且 总是 线程安全?

有帮助吗?

解决方案

解决这个特殊问题 Java并发在实践中(由基本上写的团队写作的团队编写) .concurrent库)建议延迟初始化持有者类idiom (页348在我的副本中,列出16.6,不是16.7)

@ThreadSafe
public class DBAccessServiceFactory {
  private static class ResourceHolder {
    public static DBAccessService INSTANCE = new DBAccessService();
  }
  public static DBAccessService getResource() {
    return ResourceHolder.INSTANCE;
  }
}
.

这始终是合法和线程安全的。我不是专家,所以我不能说这比你的代码更好。但是,鉴于Doug Lea和Joshua Bloch推荐的模式,我总是用它来超过你或我发明的代码,因为它很容易犯错误(如此问题的错误答案的数量所示)。

与他们说的挥发性问题有关:

jmm(java 5.0及更高版本)的后续更改已启用DCL,如果资源使得volatile vlatile ...但是延迟初始化持有者idiom提供相同的好处,更容易理解。

其他提示

您需要将生成的INSTANCE声明为for volatile,以便它工作:

private static volatile DBAccessService INSTANCE;
.

注意它仅适用于Java 5及更高版本。请参阅“双重检查锁定破坏”声明

在本文中它据称“双倍如果使用Seperate Singleton类:,则检查日志记录“不是问题

public class DBAccessHelperSingleton {
    public static DBAccessHelper instance = new DBAccessHelper(); 
} 
.

它具有相同的优势:在第一次引用之前,该字段不会实例化。

先前如前所述,如果您想要保持类似于您,则只需针对JDK>= 5.

看起来不错。如果两个线程调用 getInstance() 并且 INSTANCE 未初始化,则只有一个线程能够继续执行 createInstance(),而第二个线程将已经看到该实例不为 null。

唯一的是 volatile INSTANCE 的关键字。否则java可以缓存它。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top