首先看doublecheck的写法
public class Singleton{
//类内部创建对象实例
private static volatile Singleton instance;
//获取单例的方法
public static Singleton getSingleton() {
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();//若不加volatile,会产生指令重排序。原因是,可能先赋值地址值给instance,然后再创建对象
}
}
}
return instance;
}
/**
* 构造方法私有化,外部不能new
*/
private Singleton() {
}
/**
* 防止克隆
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return instance;
}
/**
* 防止序列化破环
*
* @return
*/
private Object readResolve() {
return instance;
}
}
在定义静态类实例的时候用了volatile来修饰
主要原因是在
instance = new Singleton();
这一步过程中可能发生指令重排序
这一步实际的操作分为三步:
1分配内存空间,属性赋默认初始值(0、false等0值);
2属性赋初值或构造函数值;
3将instance位置指向此处内存空间;
但是这三步有可能被cpu进行指重排序,导致线程1在创建instance时先1后3(则此时singleton已有null变为有真正的指向),若这时线程2得到cup进来了发现singleton已不为null,将其拿去使用的时候,则会出现问题,所以此处需要禁止指令重排序