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

Java 設計模式精講:Singleton 單例模式三種實作與最佳實踐

     編輯:Java 相關知識

核心意圖

確保類別在 JVM 中僅有一個實例,並提供全域存取點。典型應用:資料庫連線池、Socket 連線管理、設定檔載入器、JDK Collections.singleton() 內部實作。

結構圖解

  • uniqueInstance:私有靜態欄位,持有唯一實例參考。
  • getInstance():公有靜態方法,延遲初始化並回傳實例。
  • 建構子 private:防止外部直接 new。

實作一:經典延遲初始化 (Lazy Initialization)

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

缺點:多執行緒環境下可能產生多個實例 (Race Condition)。

實作二:靜態旗標 + 建構子檢查 (異常保護)

class SingletonException extends RuntimeException {
    SingletonException(String msg) { super(msg); }
}
public class Singleton {
    private static boolean instantiated = false;
    public Singleton() {
        if (instantiated) throw new SingletonException("Only one instance allowed");
        instantiated = true;
    }
}

缺點:客戶端需自行捕獲異常,API 不直覺;無法延遲初始化 (載入類別即實例化)。

實作三:登記表 (Registry) 模式 — 管理多型單例

public class SingletonRegistry {
    private static Map registry = new Hashtable<>();
    public static synchronized void register(String key, Object instance) {
        if (!registry.containsKey(key)) registry.put(key, instance);
    }
    public static synchronized Object getInstance(String key) {
        return registry.get(key);
    }
}
// 使用
SingletonRegistry.register("DBPool", new DBConnectionPool());
DBConnectionPool pool = (DBConnectionPool) SingletonRegistry.getInstance("DBPool");

優點:集中管理不同類型的單例、支援動態註冊、易於單元測試替換。

執行緒安全的現代寫法 (JDK 5+)

雙重檢查鎖定 (DCL) — volatile 關鍵

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

靜態內部類 (Initialization-on-demand Holder Idiom) — 最推薦

public class Singleton {
    private Singleton() {}
    private static class Holder { static final Singleton INSTANCE = new Singleton(); }
    public static Singleton getInstance() { return Holder.INSTANCE; }
}
  • 利用類別載入機制保證執行緒安全、延遲初始化、無同步開銷、程式碼簡潔。

Enum 單例 (Effective Java 作者 Josh Bloch 推薦)

public enum Singleton { INSTANCE; }
  • 天然防序列化破壞、防反射攻擊、語義最清晰。

常見誤區與總結

寫法執行緒安全延遲初始化防序列化破壞推薦度
懶漢式 (無同步)❌✅❌⭐
餓漢式 (靜態最終欄位)✅❌❌⭐⭐
DCL + volatile✅✅❌⭐⭐⭐
靜態內部類✅✅❌⭐⭐⭐⭐
Enum✅✅✅⭐⭐⭐⭐⭐

實務上優先考慮 Enum 或 靜態內部類;需管理多型單例時採用 Registry。

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