public class Singleton1 {
private static final Singleton1 INSTANCE = new Singleton1();
private Singleton1() {} // 私有構造器
public static Singleton1 getInstance() { return INSTANCE; }
}
public class Singleton2 {
private static Singleton2 instance;
private Singleton2() {}
public static synchronized Singleton2 getInstance() { // 整個方法同步
if (instance == null) instance = new Singleton2();
return instance;
}
}
public class Singleton3 {
private static volatile Singleton3 instance; // 關鍵: volatile 防止指令重排
private Singleton3() {}
public static Singleton3 getInstance() {
if (instance == null) { // 第一次檢查 (無鎖,快速路徑)
synchronized (Singleton3.class) { // 鎖類對象
if (instance == null) { // 第二次檢查 (併發安全)
instance = new Singleton3();
}
}
}
return instance;
}
}
public class Singleton4 {
private Singleton4() {}
// 靜態內部類,只有調用 getInstance() 時才會加載
private static class Holder {
static final Singleton4 INSTANCE = new Singleton4();
}
public static Singleton4 getInstance() {
return Holder.INSTANCE;
}
}
public enum Singleton5 {
INSTANCE;
public void doSomething() { System.out.println("Enum Singleton"); }
}
// 使用: Singleton5.INSTANCE.doSomething();
現代項目交給 IOC 容器管理單例生命周期,非手動實現。
public class ThreadLocalSingleton {
private static final ThreadLocal holder =
ThreadLocal.withInitial(ThreadLocalSingleton::new);
private ThreadLocalSingleton() {}
public static ThreadLocalSingleton getInstance() { return holder.get(); }
}
instance = new Singleton3() 非原子操作,JVM 可能重排為:
線程 A 執行到步驟 2,線程 B 進入第一次檢查看到 instance != null,直接返回半初始化對象 → 崩潰。volatile 禁止這種重排,保證構造器完成前引用不可見。
| 攻擊手段 | 原理 | 防禦 |
|---|---|---|
| 反射調用私有構造器 | ctor.setAccessible(true); ctor.newInstance() | 構造器中檢查 if (INSTANCE != null) throw... 或用枚舉 |
| 反序列化 | readObject() 返回新實例 | 實現 readResolve() 返回現有實例,或用枚舉 |
| 克隆 | 實現 Cloneable 並 clone() | 不實現 Cloneable,或 clone 拋異常 |
public class SecureSingleton implements Serializable {
private static final long serialVersionUID = 1L;
private static volatile SecureSingleton instance;
private SecureSingleton() {
// 防反射
if (instance != null) {
throw new IllegalStateException("單例已存在,禁止反射創建");
}
}
public static SecureSingleton getInstance() {
if (instance == null) {
synchronized (SecureSingleton.class) {
if (instance == null) {
instance = new SecureSingleton();
}
}
}
return instance;
}
// 防序列化破壞
protected Object readResolve() {
return instance;
}
}
| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 一般業務、工具類 | 靜態內部類 (Singleton4) | 延遲加載、線程安全、代碼簡潔、無 volatile 陷阱 |
| 高併發熱點、極致性能 | DCL (Singleton3) 或 惡漢式 (Singleton1) | 無鎖讀取、JIT 友好 |
| 安全敏感、防反射/序列化 | 枚舉 (Singleton5) | JVM 級保證、最簡潔 |
| Spring 項目 | @Component + @Scope("singleton") | 容器管理、生命周期、AOP 支持 |
單例模式看似簡單,實則蘊含 JMM 內存模型、類加載機制、反射/序列化破壞 等深層知識。理解各寫法優劣與適用邊界,是 Java 開發者進階的必修課。