为什么我们需要在锁解除之前和之后检查null?一旦我们获得了锁,没有线程能够拥有锁,那么为什么不需要在同步块之前进行空检查呢?
public class DclSingleton {
private static volatile DclSingleton instance;
public static DclSingleton getInstance() {
**if (instance == null) {**
synchronized (DclSingleton .class) {
**if (instance == null) {**
instance = new DclSingleton();
}
}
}
return instance;
}
// private constructor and other methods...
}
发布于 2019-02-20 06:50:11
想象下一个场景:
instance == null
并发现此条件为真。instance == null
并发现此条件为真。instance = new DclSingleton()
。instance = new DclSingleton()
。我们有双重初始化。发布于 2019-02-20 06:50:41
您检查了两次null
,因为:
DclSingleton.class
上进行同步之前不进行检查,那么每个调用都会被同步,这可能会很慢(想象一下经常使用单例实例)。null
块内的synchronized
,则有可能多个线程在没有机会锁定对象的情况下进行第一次检查,并且会重新创建实例。发布于 2019-02-20 07:15:48
要了解为什么需要双重null
检查,请看一下已经给出的答案。
安全初始化单个实例的另一种方法是静态holder模式,它将被如下所示:
public class DclSingleton {
public static DclSingleton getInstance() {
return Holder.INSTANCE;
}
private static class Holder {
private static final DclSingleton INSTANCE = new DclSingleton();
}
}
JVM已经以线程安全的方式初始化了类,因此即使同时有2个线程访问getInstance()
,JVM也只会初始化Holder
类一次,这样就有了正确的初始化。
另外,Holder
类将被延迟加载,因此只有在第一次引用时才会初始化它。例如,当第一次调用getInstance()
时
https://stackoverflow.com/questions/54780284
复制相似问题