Java代码实现双重检查锁(DCL)的单例模式
public class Singleton {
// 使用volatile关键字修饰单例实例
private static volatile Singleton instance;
private Singleton() {
// 私有构造函数,防止外部实例化
}
public static Singleton getInstance() {
// 第一次检查,避免不必要的同步
if (instance == null) {
synchronized (Singleton.class) {
// 第二次检查,确保在同步块内只有一个实例被创建
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
volatile关键字的作用
- 防止指令重排:在
instance = new Singleton()
这行代码中,实际上会有多个步骤,包括分配内存空间、初始化对象以及将对象引用赋值给instance
。如果没有volatile
关键字,编译器和处理器可能会对这些步骤进行重排,例如先将对象引用赋值给instance
(此时对象还未初始化完成),然后再初始化对象。当另一个线程通过第一次if (instance == null)
检查时,就可能拿到一个未初始化完全的对象。volatile
关键字可以禁止这种指令重排,保证在将instance
赋值之前,对象已经初始化完成。
- 保证可见性:当一个线程修改了
instance
的值时,volatile
关键字能确保其他线程能够立即看到这个修改。如果没有volatile
,其他线程可能无法及时感知到instance
的变化,从而导致多次创建实例,破坏单例模式。