【问题标题】:Pre-java5: Singleton pattern: Double checked Locking vs Static factory methodPre-java5:单例模式:双重检查锁定与静态工厂方法
【发布时间】:2013-11-19 17:25:14
【问题描述】:

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.4 上吗?换工作,除非他们给你很高的薪水......
  • en.wikipedia.org/wiki/Double-checked_locking 对此进行了广泛的讨论
  • @zhong.j.yu 这个问题的措辞让我觉得这是一个学术或工作面试问题,因为在java5之前有一个特定的区别。

标签: java oop design-patterns


【解决方案1】:

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

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

所有这些都只适用于你的单例当然有状态——否则,没有状态需要以线程安全的方式发布!

【讨论】:

    【解决方案2】:

    简短的回答是双重检查锁定在 Java 1.4 中不能可靠地工作。

    http://en.wikipedia.org/wiki/Double-checked_locking

    或 Java 并发实践,第 16.2 节

    长答案是@yshavit 所说的。 :-)

    【讨论】:

      【解决方案3】:

      如果Singleton_StaticFactory 有任何其他静态方法(或静态字段或公共构造函数),则调用它们将触发加载该类并初始化单例。所以在那种情况下,两者并不完全等价。否则他们就是。

      【讨论】:

      • 他谈到了 pre-java5。 DCL(双重检查锁定)在编译器中有一个重大缺陷。
      • +1。我同意 Russel Zahniser 关于为什么在访问单例类中的其他静态方法时静态工厂实现不会延迟加载的评论。谢谢!我仍然会等待其他 cmets/answers 看看是否有任何其他差异。
      • DMoses 是对的——它们相当于 1.5 之前的版本,这是问题的一部分。具体来说,在 1.4 及以下版本中,Singleton_StaticFactory 是线程安全的,而双重检查锁定则不是。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-03
      • 1970-01-01
      • 2013-08-08
      • 1970-01-01
      相关资源
      最近更新 更多