單例模式確保類別在 JVM 中僅有一個實例,並提供全域存取點。本文系統梳理七種經典寫法,從懶漢、餓漢到雙重檢查鎖、靜態內部類、枚舉,對比線程安全、延遲載入、序列化破壞、反射攻擊等關鍵指標,給出生產環境選型建議。
getInstance()。Constructor.setAccessible(true) 不能繞過。public class Emperor {
private static final Emperor INSTANCE = new Emperor();
private Emperor() {}
public static Emperor getInstance() { return INSTANCE; }
}
public class Emperor {
private static Emperor instance;
private Emperor() {}
public static synchronized Emperor getInstance() {
if (instance == null) instance = new Emperor();
return instance;
}
}
public class Emperor {
private static volatile Emperor instance; // 關鍵:volatile 禁止指令重排
private Emperor() {}
public static Emperor getInstance() {
if (instance == null) { // 第一次檢查 (無鎖)
synchronized (Emperor.class) { // 鎖定類對象
if (instance == null) { // 第二次檢查 (有鎖)
instance = new Emperor();
}
}
}
return instance;
}
}
volatile 語義修復 DCL 問題public class Emperor {
private Emperor() {}
private static class Holder {
static final Emperor INSTANCE = new Emperor();
}
public static Emperor getInstance() { return Holder.INSTANCE; }
}
public enum Emperor {
INSTANCE;
public void getName() { System.out.println("我是皇帝:明日科技"); }
}
// 使用: Emperor.INSTANCE.getName();
Constructor.newInstance() 建立枚舉public class Emperor {
private static final ThreadLocal TL = ThreadLocal.withInitial(Emperor::new);
private Emperor() {}
public static Emperor getInstance() { return TL.get(); }
}
@Component
@Scope("singleton") // 預設即為 singleton
public class Emperor { ... }
是否需防反射/序列化破壞?
├─ 是 → Enum Singleton (單一類) 或 Spring @Component (企業級)
└─ 否
├─ 需延遲載入且極簡 → Static Inner Class
├─ 需高效能併發 → DCL (volatile)
└─ 簡單工具類、無狀態 → Eager Initialization
private Emperor() { if (INSTANCE != null) throw new IllegalStateException(); } (枚舉自動處理)。readResolve() 返回現有實例。Constructor.setAccessible(true) 拋出異常 (枚舉) 或返回同一實例 (內部類 + 建構子檢查)。