双重校验锁的写法
public class Singleton {
/*
volatile 修饰,
singleton = new Singleton() 可以拆解为3步:
1、分配对象内存(给singleton分配内存)
2、调用构造器方法,执行初始化(调用 Singleton 的构造函数来初始化成员变量)。
3、将对象引用赋值给变量(执行完这步 singleton 就为非 null 了)。
若发生重排序,假设 A 线程执行了 1 和 3 ,还没有执行 2,B 线程来到判断 NULL,B 线程就会直接返回还没初始化的 instance 了。
volatile 可以避免重排序。
*/
private volatile static Singleton singleton;
private Singleton() {
}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
1 为什么要进行两次非空校验?
第一个 if 判断是为了减少性能开销
第二个 if 判断是为了避免生成多个对象实例。
2 为什么要用 volatile 关键字?
为了禁止 JVM 的指令重排,指令重排会导致对象未初始化的情况,造成报错