有这样一种基于双重检查锁定的单例实现(第 2 项):
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
Singleton localInstance = instance;
if (localInstance == null) {
synchronized (Singleton.class) {
localInstance = instance;
if (localInstance == null) {
instance = localInstance = new Singleton();
}
}
}
return localInstance;
}
}
问题1:这里有什么用localInstance?为什么不这样做:
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
?
我有一个猜测:读取volatile-field 比读取常规字段或局部变量要昂贵一些,这就是为什么在这里使用局部变量。如果我是对的,有人可以更详细地描绘这一刻——我将不胜感激。
问题2:为什么不在这个类中声明私有构造函数?实际上,如果它不存在,您可以在代码中的某处显式创建此类的实例。
这样做部分是因为性能,部分是因为如果不使用额外的局部变量,那么代码可能无法正常工作。
也就是说,如果我们写
synchronized:例如,
Singleton它将具有以下结构:也就是说,编译器可以在不保留操作顺序的情况下内联构造函数。那些。结果可能是这样的:
Singletoninstance这种情况称为不安全发布。要修复它,定义字段
final, 或volatile(有更多选项)就足够了。有关于这个主题的例子的好文章
附言。如果您有兴趣,可以运行jsctress 测试并尝试不同的变体。
localInstance需要提高此代码的性能。在它
instance已经被初始化的情况下(即在大多数情况下),这使您不能再次访问该
volatile字段,而不是
return instancereturn localInstance来源:Joshua Bloch“Effective Java,第二版”,p. 283-284
他声称这可以使生产率提高 25%。
关于第二个问题——我认为单例中的私有构造函数是理所当然的。
因此,在讨论更深层次的实现细节时,这一点可以省略。