Java 双重检查锁定
我最近偶然看到一篇文章,讨论了 Java 中的双重检查锁定模式及其陷阱,现在我想知道我多年来一直使用的该模式的变体是否会遇到任何问题.
I happened upon an article recently discussing the double checked locking pattern in Java and its pitfalls and now I'm wondering if a variant of that pattern that I've been using for years now is subject to any issues.
我查看了许多有关该主题的帖子和文章,并了解获取对部分构造对象的引用的潜在问题,据我所知,我不认为我的实施受这些问题的影响.以下模式有什么问题吗?
I've looked at many posts and articles on the subject and understand the potential issues with getting a reference to a partially constructed object, and as far as I can tell, I don't think my implementation is subject to these issues. Are there any issues with the following pattern?
如果没有,为什么人们不使用它?在我看到的有关此问题的任何讨论中,我从未见过有人推荐过它.
And, if not, why don't people use it? I've never seen it recommended in any of the discussion I've seen around this issue.
public class Test {
private static Test instance;
private static boolean initialized = false;
public static Test getInstance() {
if (!initialized) {
synchronized (Test.class) {
if (!initialized) {
instance = new Test();
initialized = true;
}
}
}
return instance;
}
}
推荐答案
双重检查锁定已损坏.由于 initialized 是一个原语,它可能不需要它是 volatile 才能工作,但是没有什么可以阻止在实例初始化之前将 initialized 视为非同步代码的真实情况.
Double check locking is broken. Since initialized is a primitive, it may not require it to be volatile to work, however nothing prevents initialized being seen as true to the non-syncronized code before instance is initialized.
为了澄清上述答案,原始问题询问了有关使用布尔值控制双重检查锁定的问题.如果没有上面链接中的解决方案,它将无法正常工作.您可以仔细检查 lock 是否实际设置了一个布尔值,但在创建类实例时仍然存在指令重新排序的问题.建议的解决方案不起作用,因为在非同步块中看到初始化的布尔值为 true 后,可能无法初始化实例.
To clarify the above answer, the original question asked about using a boolean to control the double check locking. Without the solutions in the link above, it will not work. You could double check lock actually setting a boolean, but you still have issues about instruction reordering when it comes to creating the class instance. The suggested solution does not work because instance may not be initialized after you see the initialized boolean as true in the non-syncronized block.
双重检查锁定的正确解决方案是使用 volatile(在实例字段上)并忘记初始化的布尔值,并确保使用 JDK 1.5 或更高版本,或者在 final 字段中初始化它,详细说明在链接的文章和汤姆的答案中,或者只是不使用它.
The proper solution to double-check locking is to either use volatile (on the instance field) and forget about the initialized boolean, and be sure to be using JDK 1.5 or greater, or initialize it in a final field, as elaborated in the linked article and Tom's answer, or just don't use it.
当然,整个概念似乎是一个巨大的过早优化,除非您知道在获取此 Singleton 时会发生大量线程争用,或者您已对应用程序进行了概要分析并认为这是一个热点.
Certainly the whole concept seems like a huge premature optimization unless you know you are going to get a ton of thread contention on getting this Singleton, or you have profiled the application and have seen this to be a hot spot.
相关文章