典型應用:線程池、快取、日誌、對話框、列印機、驅動程式——資源管理器角色,避免狀態不一致與重複佔用。
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return INSTANCE; }
}
public class Singleton {
private static volatile Singleton instance; // volatile 禁止指令重排
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次檢查(無鎖,效能)
synchronized (Singleton.class) { // 類級別鎖
if (instance == null) { // 第二次檢查(鎖內)
instance = new Singleton(); // 非原子操作:分配記憶體→初始化→賦值
}
}
}
return instance;
}
}
public class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
getInstance() 才觸發 Holder 初始化public enum Singleton {
INSTANCE;
private Connection conn;
Singleton() { // 建構子自動執行
// 初始化資源(如資料庫連線)
}
public Connection getConnection() { return conn; }
}
// 使用
Singleton.INSTANCE.getConnection();
Constructor.newInstance() 拋異常)public class ConnectionFactory {
private enum Singleton { INSTANCE; ... }
public static Connection getConnection() {
return Singleton.INSTANCE.getConnection();
}
}
public class Singleton {
private static Singleton instance;
private Singleton() {}
static { // 類載入時執行,線程安全
instance = new Singleton();
}
public static Singleton getInstance() { return instance; }
}
問題:預設反序列化會創建新實例,破壞單例。
public class Singleton implements Serializable {
private static final long serialVersionUID = 1L;
private static class Holder { static final Singleton INSTANCE = new Singleton(); }
private Singleton() {}
public static Singleton getInstance() { return Holder.INSTANCE; }
// 關鍵:反序列化時返回唯一實例
protected Object readResolve() {
return Holder.INSTANCE;
}
}
readResolve():反序列化時自動調用,返回規定實例| 方式 | 線程安全 | 延遲載入 | 防反射 | 防序列化破壞 | 複雜度 | 推薦場景 |
|---|---|---|---|---|---|---|
| 餓漢式(常量) | ✅ | ❌ | ❌ | ❌ | 低 | 輕量級、必用 |
| DCL | ✅ | ✅ | ❌ | ❌ | 中 | 高併發、需延遲 |
| 靜態內部類 | ✅ | ✅ | ❌ | ❌1 | 低 | 通用首選 |
| 枚舉 | ✅ | ✅ | ✅ | ✅ | 極低 | 最強健 |
| 靜態代碼塊 | ✅ | ❌ | ❌ | ❌ | 低 | 複雜初始化 |
readResolve() 達到防序列化破壞
單例模式看似簡單,實則蘊含 Java 記憶體模型、類載入機制、反射、序列化等核心知識。選對方式,才能在高併發生產環境穩如磐石。