Double-Check提供了一种高效的数据同步策略,那就是首次初始化时加锁,之后则允许多个线程同时执行getInstance方法的调用来获得类的实例。示例代码如下:
public final class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance(){
if(null == instance){
synchronized(Singleton.class){
if(null == instance){
instance = new Singleton()
}
}
}
return instance;
}
}
当两个线程发现null == instance成立时,只要一个线程有资格进入同步代码块,完成对instance的初始化,随后的线程发现null == instance 不成立时,无需进行任何操作,以后对getInstance的访问就不需要数据同步的保护了。
但是这种设计模式容易出现空指针异常,当Singleton中有多个资源需要初始化时,由于happens-before和指令重排序会导致instance先实例化,而其他资源在初始化之前被调用了,这时会出现空指针异常。