这段代码是否解决了Java中的双重检查锁定问题?
这段代码是否解决了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;
}
}
有两个方面需要注意:
getInstance()
是不同步的,因此 INSTANCE 初始化后,同步createInstance()
是没有任何成本的是同步的
那么,问题是:这段代码有什么问题吗?它是否合法且始终线程安全?
Does this code solve the double checked locking issue in 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;
}
}
There are 2 aspects to pay attention:
getInstance()
is not synchronized, so after INSTANCE is initialized there is no cost for synchronizationcreateInstance()
is synchronized
So, the question is: does this code have any issues? Is it legal and always thread-safe?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您需要将
INSTANCE
声明为volatile
才能正常工作:请注意,它仅适用于 Java 5 及更高版本。请参阅“双重检查锁定已损坏”声明。
You need to declare
INSTANCE
asvolatile
for it to work:Note it only works with Java 5 and later. See The "Double-Checked Locking is Broken" Declaration.
为了解决这个特定问题实践中的Java并发(由基本上编写java.util.concurrent库的团队编写)推荐延迟初始化持有者类习惯用法(我的副本中的第348页,清单16.6,而不是16.7)
这始终是合法且线程安全的。我不是专家,所以我不能说这比你的代码更好。然而,考虑到这是 Doug Lea 和 Joshua Bloch 推荐的模式,我总是会在你或我发明的代码上使用它,因为它很容易犯错误(正如这个问题的错误答案数量所证明的那样) )。
关于不稳定的问题,他们说:
For solving this particular question Java concurrency in practice (written by the team who basically wrote the java.util.concurrent library) recommends the Lazy Initialization holder class idiom (page 348 in my copy, Listing 16.6, not 16.7)
This is always legal and Thread-safe. I'm not an expert, so I can't say this is better than your code. However, given that it is the pattern recommended by Doug Lea and Joshua Bloch, I'd always use it over code you or I have invented, as it is so easy to make mistakes (as demonstrated by the number of wrong answers to this question).
Related to the volatile issue they say:
在本文中声称“双重检查日志记录”如果您使用单独的 Singleton 类,这不是问题:
它具有相同的优点:该字段在第一次引用之前不会实例化。
如前所述,如果您想保持现有状态,则在您仅针对 JDK >= 5 的情况下缺少
易失性
。In this article it is claimed that "double checked logging" is not an issue if you use a seperate Singleton class:
It has the same advantage: The field is not instantiated before being references the first time.
As stated previously, if you want to keep like you have it
volatile
is missing in case you are only targetting JDK >= 5.它不是线程安全的,请查看一篇优秀的文章 。无法保证一个线程会看到完全初始化的 DbAccessService 实例。为什么不使用简单的
It is not thread safe, please check an excelent article. There is no guarantee, that one thread will see fully initialized instance of DbAccessService. Why not using simple
看起来不错。
如果两个线程调用 getInstance() 并且 INSTANCE 未初始化,则只有一个线程能够继续执行 createInstance(),而第二个线程将已经看到该实例不为 null。
唯一的事情是 INSTANCE 的
volatile
关键字。否则java可以缓存它。Looks fine.
If two threads call getInstance() and INSTANCE is not initalized, only one thread will be able to proceed with createInstance() and the second one will already see that instance is not null.
The only thing is
volatile
keyword for INSTANCE. Otherwise java can cache it.