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

深度解析 Java SE 單例設計模式的七種實現方式

     編輯:Java 相關知識

Java 單例模式全景指南:從餓漢到註冊式

單例模式確保類在 JVM 中僅有一個實例,並提供全局訪問點。它是最基礎也最常考的設計模式,但在多線程、序列化、反射攻擊等場景下隱藏諸多陷阱。

核心三要素

  1. 私有構造器(防止外部 new)
  2. 靜態私有實例變量
  3. 公開靜態獲取方法(getInstance())

七種經典實現深度剖析

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. 雙重檢查鎖(DCL)

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;
    }
}

關鍵:volatile 禁止指令重排,保證初始化可見性。JDK 1.5+ 修復內存模型後才可靠。

4. 靜態內部類(推薦)

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

優勢:利用類加載機制天然線程安全、延遲加載、無鎖高效、防序列化/反射破壞(需額外處理)。

5. 枚舉單例(Effective Java 推薦)

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

終極防線:JVM 保證單例、免費防序列化破壞、防反射攻擊、代碼最簡潔。

6. 註冊式/容器式單例

Spring 容器本質即單例註冊表。自定義實現可用 ConcurrentHashMap 存儲 ClassName -> Instance,支援多單例管理、動態註冊銷毀,適合插件化架構。

7. ThreadLocal 線程單例

public class ThreadLocalSingleton {
    private static final ThreadLocal<ThreadLocalSingleton> HOLDER = 
        ThreadLocal.withInitial(ThreadLocalSingleton::new);
    private ThreadLocalSingleton() {}
    public static ThreadLocalSingleton getInstance() { return HOLDER.get(); }
}

場景:每個線程擁有獨立實例,如數據庫連接、Session 上下文、請求級緩存。

破壞單例與防護

攻擊手段防護措施
反射調用私有構造器構造器中檢查 instance != null 拋出異常
序列化/反序列化實現 readResolve() 返回同一實例
跨類加載器指定上下文類加載器、雙親委派模型

選型建議

  • 一般業務:靜態內部類或枚舉
  • 需延遲加載且極致性能:DCL + volatile
  • 框架/容器開發:註冊式
  • 線程隔離場景:ThreadLocal
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved