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/