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

Java 單例模式(Singleton Pattern)核心原理與線程安全實作範例

     編輯:Java 相關知識

模式定義

確保一個類全局僅有一個實例,並提供全局訪問點。適用於:配置管理器、連接池、線程池、日誌記錄器、緩存管理器等。

七種經典實現對比

1. 餓漢式(類加載時創建,天然線程安全)

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

優點:簡單、無鎖、效能最高。缺點:類加載即創建,若實例極重且未必使用,浪費記憶體。

2. 懶漢式 + synchronized(線程安全但效能低)

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

每次調用加鎖,高併發下嚴重影響吞吐。

3. 雙重檢查鎖(DCL,JDK 1.5+ volatile 修復指令重排)

public class SingletonDCL {
    private static volatile SingletonDCL instance; // 關鍵 volatile
    private SingletonDCL() {}
    public static SingletonDCL getInstance() {
        if (instance == null) {                 // 第一次檢查(無鎖)
            synchronized (SingletonDCL.class) { // 鎖定類對象
                if (instance == null) {         // 第二次檢查(鎖內)
                    instance = new SingletonDCL();
                }
            }
        }
        return instance;
    }
}

兼顧延遲初始化與高併發效能,是面試與工程常用寫法。

4. 靜態內部類(推薦:延遲加載 + 線程安全 + 代碼簡潔)

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

利用類加載機制:外部類加載時不初始化內部類,首次調用 getInstance() 觸發 Holder 初始化,JVM 保證線程安全。

5. 枚舉單例(Effective Java 推薦,防反射/序列化破壞)

public enum SingletonEnum {
    INSTANCE;
    public void doSomething() { System.out.println("do something"); }
}

優點:語法最簡、天然防序列化重新創建實例、防反射攻擊(構造器私有化)。缺點:不支援延遲加載、無法繼承、無法實現複雜初始化邏輯。

6. 容器管理(Spring @Component + @Scope("singleton"))

現代框架開發中,交由 IoC 容器管理單例生命週期,配合 @PostConstruct 初始化、@PreDestroy 銷毀,最符合工程實踐。

破壞單例的攻擊與防禦

選型建議

  • 一般業務工具類 → 靜態內部類 或 枚舉。
  • 需複雜初始化、依賴注入 → Spring 容器單例 Bean。
  • 極致效能、確定會使用 → 餓漢式。
  • 面試考察 DCL 細節 → 熟練寫出 volatile + 雙重檢查。

總結

單例模式看似簡單,實則蘊含「線程安全、延遲加載、防破壞、容器整合」多維考量。理解各實現優劣與適用邊界,才能在實際架構中做出最優決策。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
攻擊手段受影響實現防禦
反射調用私有構造器除枚舉外所有構造器中檢查 if (instance != null) throw new IllegalStateException()
序列化/反序列化實現 Serializable 的單例實現 readResolve() 返回現有實例;或用枚舉
多類加載器所有靜態字段單例指定統一類加載器、或使用容器管理