1. 问题描述
Double-Checked Locking(双重检查锁) 用在多线程环境中实现延迟初始化的有效方法,但编译器为了优化性能,存在指令重排序问题,可能会导致双重检查锁失效 (Double-Checked Locking is Broken)
2. 问题场景
在单例模式中,开发进程采用双重检查锁来确保只创建一个实例
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if(instance == null) {
// 此处在创建对象操作存在问题,会导致双重检查锁失效
instance = new Singleton();
}
}
}
return instance;
}
}
instance = new Singleton()
实际上可以分解成以下三个步骤
- 1.分配内存空间
- 2.初始化对象
- 3.将对象指向刚分配的内存空间
但是编译器为了性能的原因,可能会将第 2 步和第 3 步进行重排序,顺序就成了
- 1.分配内存空间
- 2.将对象指向刚分配的内存空间
- 3.初始化对象
3. 修复方案
将private static Singleton instance = null;
中的 instance 使用 volatile 修饰,重排序被禁止,所有的写 (write) 操作都将发生在读 (read) 操作之前
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}