1.关于双检测锁定DCL的问题
public class SingletonKerriganD {
/**
* 单例对象实例
*/
private static SingletonKerriganD instance = null;
public static SingletonKerriganD getInstance() {
if (instance == null) {
synchronized (SingletonKerriganD.class) {
if (instance == null) {
instance = new SingletonKerriganD(); //A
}
}
}
return instance;
}
}
A处的代码的汇编大致执行如下几步
1.分配内存
2.初始化
3.变量指向这个内存
在java上由于支持处理器乱序执行,2和3的顺序是不定的,假如3先执行了,那么第二个线程在访问的时候会因为变量不为空直接返回,但这时还没有初始化,所以可以遇见的一定会报错。
在c语言中是可行的,在java1.5以后呢引入了volatile ,volatile修饰的变量,保证每次都从堆中读取,保证在2,3没有完全执行完的时候不会有人可以访问到他。会影响一定的效率
那么可以采用内部静态类的方式。
public class SingletonKerrigan implements Serializable {
private static class SingletonHolder {
/**
* 单例对象实例
*/
static final SingletonKerrigan INSTANCE = new SingletonKerrigan();
}
public static SingletonKerrigan getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* private的构造函数用于避免外界直接使用new来实例化对象
*/
private SingletonKerrigan() {
}
/**
* readResolve方法应对单例对象被序列化时候
*/
private Object readResolve() {
return getInstance();
}
}