这段代码是否解决了Java中的双重检查锁定问题?
-
12-11-2019 - |
题
这段代码是否解决了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个方面需要注意:
getInstance()
是 不是 同步,因此实例初始化后没有同步成本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可以缓存它。
不隶属于 StackOverflow