gpt4 book ai didi

java - 在Java中使用基于双重检查锁定的单例是否安全?

转载 作者:行者123 更新时间:2023-12-02 08:48:36 25 4
gpt4 key购买 nike

Wikipedia 上列出了 Java 中 Singleton 的实现之一。 :

public class SingletonDemo {
private static volatile SingletonDemo instance = null;

private SingletonDemo() {
}

public static SingletonDemo getInstance() {
if (instance == null) {
synchronized (SingletonDemo.class) {
if (instance == null) {
instance = new SingletonDemo();
}
}
}
return instance;
}
}

Java Language Specification 17, paragraph 5指出

An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.

好吧,假设我们的 SingletonDemo 类有非 Final 字段。那么,并发线程将能够读取默认值而不是构造函数中指定的正确值?

最佳答案

在 Java 5 及更高版本中可以正确实现双重检查锁定 (DCL)。在 Java 4 及更早版本中,这是不可能的,因为 volatile 在同步方面的行为没有正确指定(并且在实践中是不充分的)。

您问题中包含的代码是 DCL 的正确实现...当使用 Java 5 JRE 或更高版本运行时。

但是(IMO),不值得使用 DCL。特别是如果您(或您之后的开发人员)不完全理解如何正确/安全地做到这一点。

性能优势太小,在现实的 Java 应用程序中不值得进行优化。 (如果是的话,您可能过度使用/滥用单例......这会以其他方式困扰您!)

<小时/>

Ok, so imagine that our SingletonDemo class has non-final field. So, concurrent thread will be able to read default value instead of correct value specified in constructor?

(引用的 JLS 文本是关于完全不同的情况。它是关于 final 字段的。它与此处无关。并且您无法推断非 final 的行为> 具有同步的字段与不具有同步的 final 字段的行为。)

您的问题的答案是否定的。您问题中的代码足以保证并发线程不会看到默认值。要了解原因,请阅读以下内容:

  • JLS 第 17.4 条的全部内容,以及
  • Goetz 等人的《Java 并发实践》的最后一章,其中包含有关 DCL 的部分(如果我没记错的话……)

关于java - 在Java中使用基于双重检查锁定的单例是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21374188/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com