当需要单身时,静态字段是一个优雅的解决方案吗?
class HelperSingleton {
static Helper singleton = new Helper();
public static Helper getInstance() {
return singleton;
}
}
当两个线程同时访问getInstance
时,字段singleton
是否有可能未完全初始化?或者查看辅助对象的字段的默认值,而不是构造函数中设置的值?
静态单例也是懒惰初始化?
static Helper singleton = new Helper();
这个分配是原子的吗?并且不会返回默认值?
答案 0 :(得分:1)
我认为单身人士最优雅的解决方案是:
public enum Singleton {
INSTANCE;
public Singleton getInstance() {
return INSTANCE;
}
}
使用单例模式有些问题,因为有时您不知道真正只有其中一个。例如,当您使用类加载器时,请考虑这种情况。
This问题(以及其他问题)顺便说一下。
答案 1 :(得分:1)
1)当线程访问静态getInstance时,第一次类加载器必须加载HelperSingleton类,它将在加载类之前锁定其他线程。因此存在隐式同步。 J.Bloch“Effective Java”Item 71 现代VM将仅同步字段访问以初始化类。初始化类后,VM将修补代码,以便后续访问该字段不涉及任何测试或同步。
2)你的单身人员很懒,因为只有一个接入点 - getInstance。不仅按需创建实例,而且按需加载整个类。一个类不会被初始化 直到它被使用[JLS,12.4.1]。
答案 2 :(得分:0)
查看http://en.wikipedia.org/wiki/Singleton_pattern
有很多样式可以解释好/坏。
答案 3 :(得分:0)
如果是这样的话:
class HelperSingleton {
static Helper singleton = null;
public static Helper getInstance() {
if(singleton == null) {
singleton = new Helper();
}
return singleton;
}
}
这里可能存在这样的可能性:
线程1调用getInstance()
方法并确定singleton
为null
。
线程1进入if块,但在创建新实例之前被线程2抢占。
线程2调用getInstance()
方法并确定该实例为null
。
线程2进入if块并创建一个新的Helper
对象,并将变量singleton
分配给此新对象。
线程2返回Singleton对象引用。
线程2被线程1抢占。
线程1从它停止的地方开始并执行singleton = new Helper();
,这导致创建另一个Singleton对象。
线程1返回此对象。
所以我们最终得到了两个实例。创建单身人士的最佳方式是使用枚举作为已回答here。
static Helper singleton = new Helper();
此处加载类时会创建Helper
的新实例,singleton
保存对该实例的引用。您可以在JLS 12.4.2中获得详细的初始化过程。