Singleton模式
问题描述:
下面的片段是直线前进,Singleton模式
public MyClass getInstance() {
if(uniqueInstance == null) {
uniqueInstance = new MyClass();
}
return uniqueInstance;
}
什么是以下一种呢?
public MyClass getInstance() {
if(uniqueInstance == null) {
synchronized(MyClass.class) {
uniqueInstance = new MyClass();
}
}
return uniqueInstance;
}
答
这是一个很差的尝试,以使其线程安全,以防止由至少两个线程同时进入if
块造成的竞争条件。
更安全一点的方法是添加额外的空检查,也称为double-checked locking。
public MyClass getInstance() {
if (uniqueInstance == null) {
synchronized(MyClass.class) {
if (uniqueInstance == null) {
uniqueInstance = new MyClass();
}
}
}
return uniqueInstance;
}
但是,我通常更喜欢Just Create One pattern而不是Singleton。
答
这是一个线程安全的保险。
从和javaworld文章here:
同步的方法保证 是对方法的调用不能 中断。
主要的想法是,如果你没有在synchronized块是可能的2个线程调用的getInstance并重新初始化对象,从而可能丢失任何状态数据(如果你甚至应该有状态数据一个单身人士)
答
第二个做同样的事情,除了:如果您使用第一个,如果创建一个新的MyClass需要一定的时间,并且在此期间,其他人也会调用MyClass.getInstance() ?你可能会结束两个实例。第二个版本锁定实例化行,这样如果另一个类尝试同时调用,它将等到第一个完成。
答
恕我直言,你应该首先从最简单的选项开始。最简单的单例是带有一个条目的枚举。鉴于类是负载懒惰,这仍然会给你懒加载,除非直接引用类,这不容易发生意外。
enum Singleton {
INSTANCE;
}
为避免意外加载,您可以使用内部类。
class Singleton {
static class SingeltonHolder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
注意;这两个解决方案都不需要同步,因为它们使用类加载是线程安全的事实。
总之;有些情况下需要锁定,但不要使它比需要更复杂。
“更安全一点”...我不太确定:http://www.google.ca/search?q=double+checked+locking+is+broken – 2010-12-05 06:05:48