public class Singleton {
// volatile 保证可见性和禁止指令重排序
private static volatile Singleton singleton;
// 将构造器的修饰符设置为"private",可以防止在外部进行new实例对象
private Singleton() {
};
public static Singleton getInstance() {
// 第一次检查
if (singleton == null) {
// 同步代码块
synchronized(this.getClass()) {
// 第二次检查
if (singleton == null) {
// 对象的实例化是一个非原子性操作
singleton = new Singleton();
}
}
}
return singleton;
}
}
如果不进行第二次判空的话,那么在竟锁池((锁池)中如果还有活跃的线程在等待获取的锁的话,在锁释放后就会再次竞争获取锁,获取的锁的线程进入"就绪状态",当CPU分配其"时间片"后进行线程的调度,从而线程进入"运行中状态",并会去执行同步的代码块,如果在没加如二次判空的话,就会导致系统中存在多个实例,而在进行判空后,即使你获取到了锁,但在执行同步代码块时也会直接跳过。
第一次判空是非必须的(优化) 第二次判空是必须的