java - java5 之前的版本 : Singleton pattern: Double checked Locking vs Static factory method

标签 java oop design-patterns

JSE5 之前的版本:

以下两种在 Pre-JSE5 中实现单例设计模式的方法有什么区别?在我看来,两者都只是延迟加载。

即使静态工厂方法也不是延迟加载,还有什么区别?

双重检查锁定方法:

public class Singleton {
  private static volatile Singleton sic; 
  private Singleton() {}

  public static Singleton getInstance() {
    if (sic == null) {
      // Let's make it thread safe using 'synchronized'
      synchronized(Singleton.class) {
        if (sic == null) {
          sic = new Singleton();        
        }
      }
    }
    return sic;
  }
}

静态工厂方法

public class Singleton_StaticFactory {
  private static final Singleton_StaticFactory s = new Singleton_StaticFactory();
  private Singleton_StaticFactory() {}
  public static Singleton_StaticFactory getInstance() {
    return s;
  }
}

更新

Russell Zahniser 在他的回答中解释了为什么静态工厂实现会以一种不需要的方式提前加载单例,而其他静态方法(如果存在)会在“getInstance”方法之前访问。因此,与我上面所说的不同,两者在“延迟初始化”方面并不相同。

我仍然想知道是否还有其他差异。

最佳答案

在 Java 1.5 之前,写入 volatile 之间没有发生之前边缘。字段和从同一字段读取。因此,假设线程 A 调用 getInstance() ,参见sic == null并实例化一个新的 Singleton并将其分配给 sic 。稍后,线程 B 调用 getInstance() ,参见sic != null并返回它而不经过 synchronized block 。在这种情况下,线程 A 创建 sic 之间没有发生边缘。和线程 B 读取它。这意味着除非 Singleton即使面对不安全的发布(大多数对象都不是),也是线程安全的,存在竞争条件并且代码不是线程安全的。

此外,在没有安全发布的情况下使对象线程安全的方法之一是标记其所有字段 final 。这确保任何读取 final 之一的对象fields 将看到其在构造函​​数末尾的状态(只要您不将 this 泄漏到构造函数之外)。但这种保证本身只是在 Java 1.5 中添加的。这意味着在Java 1.5之前,在没有安全发布的情况下,确实没有任何方法可以使对象安全,因此双重检查锁始终是不安全的。

当然,所有这些仅适用于您的单例有状态的情况 - 否则,没有状态需要线程安全地发布!

关于java - java5 之前的版本 : Singleton pattern: Double checked Locking vs Static factory method,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20077991/

相关文章:

java - 当我将某些类变量重新分配给新对象时会发生什么?

java - 为什么在单例类中必须有私有(private)构造函数

design-patterns - 单一职责原则与 Move 方法重构

Java JComboBox数组只显示一个元素

java - 如何用java实现聚类图

java - 如何使 java.awt Graphics2D 字符串出现在小程序中的随机位置

java - 使用Java加密/解密pdf文件

php - 关联数组与 SplObjectStorage

javascript - JS 获取并使用父对象的变量

c++ - 接口(interface)膨胀需要修剪