public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return INSTANCE; }
}
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) instance = new Singleton();
return instance;
}
}
volatile)public class Singleton {
private volatile static 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() 非原子操作:① 分配內存 ② 初始化對象 ③ 引用指向內存。無 volatile 時,JVM 可能重排為 ①→③→②,導致線程 B 看到 instance != null 但對象未初始化完成,直接返回半成品對象。volatile 禁止重排,保證 happens-before 可見性。
public class Singleton {
private Singleton() {}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() { return Holder.INSTANCE; }
}
Holder,真正調用 getInstance() 才觸發內部類加載 → 延遲加載volatile 複雜性readResolve())| 模式 | 延遲加載 | 線程安全 | 效能 | 複雜度 | 推薦指數 |
|---|---|---|---|---|---|
| 餓漢式 | ❌ | ✅ | 高 | 低 | ⭐⭐⭐ |
| 懶漢式(同步) | ✅ | ✅ | 低 | 低 | ⭐ |
| DCL | ✅ | ✅ | 高 | 中 | ⭐⭐⭐⭐ |
| 靜態內部類 | ✅ | ✅ | 高 | 低 | ⭐⭐⭐⭐⭐ |
// 構造器中添加防禦
private Singleton() {
if (Holder.INSTANCE != null) throw new IllegalStateException("已存在實例");
}
// 實現 readResolve 防反序列化創建新對象
private Object readResolve() { return Holder.INSTANCE; }
日常開發首選靜態內部類,兼顧延遲加載、線程安全、高效能、代碼簡潔。若極度追求啟動速度且實例輕量,餓漢式也可接受。DCL 僅在需精確控制初始化時機(如依賴外部配置)時考慮。切記:雙重檢查鎖少寫 volatile 是生產事故高發區。