aka*_*lou 5 java singleton thread-safety double-checked-locking
此代码是否解决了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;
}
}
Run Code Online (Sandbox Code Playgroud)
有两个方面需要注意:
getInstance()
是不同步的,所以INSTANCE被初始化之后没有用于同步没有成本createInstance()
是同步的所以,问题是:这段代码有什么问题吗?它合法且始终是线程安全的吗?
需要声明INSTANCE
的volatile
,它的工作:
private static volatile DBAccessService INSTANCE;
Run Code Online (Sandbox Code Playgroud)
请注意,它仅适用于Java 5及更高版本.请参阅"双重检查锁定已损坏"声明.
为了解决这个特定问题,Java 并发实践(由基本上编写 java.util.concurrent 库的团队编写)推荐使用延迟初始化持有者类习惯用法(我的副本中的第 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;
}
}
Run Code Online (Sandbox Code Playgroud)
这始终是合法且线程安全的。我不是专家,所以我不能说这比你的代码更好。然而,考虑到这是 Doug Lea 和 Joshua Bloch 推荐的模式,我总是会在你或我发明的代码上使用它,因为它很容易出错(正如这个问题的错误答案数量所证明的那样) )。
关于不稳定的问题,他们说:
JMM(Java 5.0 及更高版本)中的后续更改使得 DCL 能够在资源变得易失性的情况下工作...但是,惰性初始化持有者习惯用法提供了相同的好处并且更容易理解。