首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 設計優化:單例模式五種實現深度比較與選型指南

     編輯:Java 相關知識

單例模式核心價值

  • 受控訪問:全局唯一訪問點
  • 資源節約:避免重複創建昂貴對象(連接池、緩存、配置管理器)
  • 狀態共享:協調全局狀態

五種經典實現

1. 餓漢式


public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() { return INSTANCE; }
}

特點:類加載時初始化、線程安全、無同步開銷。
缺點:無延遲加載、異常處理困難。

2. 懶漢式 + 同步方法


public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if (instance == null) instance = new Singleton();
        return instance;
    }
}

特點:延遲加載、線程安全。
缺點:每次調用同步、效能極差。

3. 靜態內部類


public class Singleton {
    private Singleton() {}
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() { return Holder.INSTANCE; }
}

原理:JVM 類加載機制保證線程安全與延遲初始化。
優點:線程安全、延遲加載、無同步開銷、代碼簡潔。
推薦:⭐⭐⭐⭐⭐

4. 雙重檢查鎖


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` 禁止指令重排。
優點:延遲加載、高併發效能較好。
缺點:代碼較複雜、JDK 5+ 才可靠。

5. 枚舉單例


public enum Singleton {
    INSTANCE;
    public void doBusiness() {}
}

優點:防反射破壞、防序列化破壞、線程安全、語法最簡潔。
推薦:⭐⭐⭐⭐⭐ (Josh Bloch 推薦)

效能與特性對比

實現線程安全延遲加載效能防反射防序列化代碼複雜度
餓漢式✓✗極高✗需 readResolve低
同步方法✓✓低✗需 readResolve低
靜態內部類✓✓極高✗需 readResolve低
DCL✓ (JDK5+)✓高✗需 readResolve中
枚舉✓✓極高✓✓極低

防破壞加強


// 反射攻擊防禦 (非枚舉)
private Singleton() {
    if (instance != null) throw new IllegalStateException("單例已存在");
}

// 序列化破壞防禦
private Object readResolve() { return INSTANCE; }

// 克隆破壞防禦
@Override protected Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException("單例不可克隆");
}

選型決策樹

  1. Spring/Guice 管理?→ 是 → `@Singleton` 註解
  2. 需絕對防反射/序列化?→ 是 → 枚舉
  3. 需延遲加載?→ 是 → 靜態內部類 (首選) 或 DCL
  4. 確定會用、初始化輕量?→ 餓漢式
  5. 極致熱點路徑、JDK 5+?→ DCL

實戰應用場景

  • 配置管理器 (`ConfigManager.getInstance()`)
  • 連接池 (`DataSource.getInstance()`)
  • 緩存管理器 (`CacheManager.getInstance()`)
  • 日誌工廠 (`LoggerFactory.getInstance()`)
  • ID 生成器 (`IdGenerator.getInstance()`)
  • 線程池管理器 (`ThreadPoolManager.getInstance()`)

現代替代:依賴注入容器


// Spring
@Component @Scope("singleton")
public class ConfigManager { ... }

// 使用處注入
@Autowired ConfigManager configManager;

容器管理生命週期、依賴關係、AOP 代理、測試替換,優於手寫單例。

總結

「單例模式理解容易,正確實現難。現代 Java 開發中,優先交給 DI 容器管理;必須手寫時,枚舉與靜態內部類是最佳平衡點。」

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved