以下代码段是直截了当的,
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;
}
答案 0 :(得分:5)
尝试使线程安全,以防止由至少两个同时进入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而非单身人士。
答案 1 :(得分:3)
这对于线程安全来说有点保险。
来自javaworld文章here:
同步方法保证 调用方法不能 中断。
主要思想是,如果你没有synchronized块,那么2个线程可以调用getInstance并重新初始化对象,从而可能丢失任何状态数据(如果你甚至应该在单例中有状态数据)
答案 2 :(得分:3)
恕我直言你应该先从最简单的选项开始。最简单的单例是一个带有一个条目的枚举。鉴于类是懒惰加载,这仍然会给你延迟加载,除非直接引用类,这不容易发生。
enum Singleton {
INSTANCE;
}
为避免意外加载,您可以使用内部类。
class Singleton {
static class SingeltonHolder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
请注意;两种解决方案都不需要同步,因为它们使用了类加载是线程安全的事实。
总之;在某些情况下需要锁定,但不要使其比需要的更复杂。
答案 3 :(得分:1)
第二个做同样的事情,除了:如果你使用第一个,如果创建一个新的MyClass需要一些时间会发生什么,在那段时间,其他人也会调用MyClass.getInstance()?您可能最终得到两个实例。第二个版本锁定实例化行,因此如果另一个类试图同时调用,它将等到第一个完成。