Double Check Lock(DCL) (不推荐)
public class DCLSingleton {
private static DCLSingleton sSingleton; // 存在风险
// private volatile static DCLSingleton sSingleton; // 避免风险
private DCLSingleton() {
}
public DCLSingleton getInstance() {
if (sSingleton == null) {
synchronized (DCLSingleton.class) {
if (sSingleton == null) {
sSingleton = new DCLSingleton();
}
}
}
return sSingleton;
}
}
DCL失效问题
sSingleton = new DCLSingleton();看起来是一句代码,但实际上并不是一个院子操作,这句代码最终会被编译成多条汇编指令,大致做了3件事情:
(1)给Singleton的实例分配内存;
(2)调用Singleton()的构造函数,初始化成员变量;
(3)将sInstance对象指向分配的内存空间(此时sInstance就不是null了)。
由于Java编译器允许处理器乱序执行,(2)(3)执行顺序无法得到保证。如果在线程A执行1-3-2, 在3执行完了,2执行之前的时候,线程B调用getInstance,取走了一不为空,但没有实例化完成的instance,就会出错。这就是DCL失效问题。
使用volatile关键字可以保证sInstance每次都从主内存中读取,避免上述问题,但会牺牲一定的性能。
静态内部类单例模式(推荐)
public class InnerClassSingleton {
private static InnerClassSingleton sInstance;
private InnerClassSingleton() {
}
private static class SingletonHolder {
private static final InnerClassSingleton sInstance = new InnerClassSingleton();
}
public InnerClassSingleton getInstance() {
return SingletonHolder.sInstance;
}
}
参考
《Android源码设计模式解析与实战》