單例模式確保一個類在整個 JVM 進程中只存在一個實例,並提供全局訪問點。適用於需要頻繁創建/銷毀、創建耗時較大或需要共享資源的場景(如線程池、緩存、配置管理器)。
new 創建實例。getInstance() 返回該實例。public class SingletonEager {
// 1. 私有構造器
private SingletonEager() {}
// 2. 類加載時立即創建實例(線程安全)
private static final SingletonEager INSTANCE = new SingletonEager();
// 3. 靜態工廠方法
public static SingletonEager getInstance() {
return INSTANCE;
}
}
優點:實現簡單,由 JVM 類加載機制天然保證線程安全。
缺點:若實例從未被使用,會造成記憶體浪費;無法實現延遲加載。
public class SingletonLazy {
private static SingletonLazy instance = null;
private SingletonLazy() {}
// 非線程安全版本
public static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
優點:延遲加載,按需創建。
缺點:多線程環境下會創建多個實例(線程不安全)。
public static synchronized SingletonLazy getInstance() { ... }
public static SingletonLazy getInstance() {
if (instance == null) { // 第一次檢查
synchronized (SingletonLazy.class) { // 加鎖
if (instance == null) { // 第二次檢查
instance = new SingletonLazy();
}
}
}
return instance;
}
注意:instance 必須聲明為 volatile,防止指令重排導致對象未完全初始化即被其他線程看到。
public class SingletonHolder {
private SingletonHolder() {}
private static class Holder {
static final SingletonHolder INSTANCE = new SingletonHolder();
}
public static SingletonHolder getInstance() {
return Holder.INSTANCE;
}
}
利用類加載機制同時實現延遲加載與線程安全,代碼簡潔高效。

| 場景 | 推薦實現 |
|---|---|
| 實例創建開銷小、必定會用到 | 餓漢式 |
| 實例創建開銷大、可能不會用到 | 靜態內部類 / DCL |
| 需要序列化/反序列化保持單例 | 實現 readResolve() 或使用枚舉 |
| 防止反射攻擊 | 枚舉單例 enum Singleton { INSTANCE; } |
實際開發中,靜態內部類與枚舉是最佳實踐,兼顧性能、線程安全與代碼簡潔性。