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

Java 設計模式精講:單例模式的六種寫法與最佳實踐

     編輯:Java 綜合教學

什麼是單例模式?

單例模式屬於創建型模式,確保某個類在整個應用程式生命週期中只有一個實例,並提供全域存取點。常見場景:資料庫連線池、日誌物件、配置管理器等資源密集型物件。

核心要素

  1. 私有化建構子,防止外部 new 實例。
  2. 靜態私有實例變數持有唯一物件。
  3. 公開靜態方法(慣用 getInstance())回傳實例。

六種經典實現方式深度解析

1. 懶漢式(線程不安全)❌

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

缺陷:多線程並發時會創建多個實例,嚴格意義上不算單例。

2. 懶漢式(同步方法,線程安全但效率低)🐢

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

每次呼叫都加鎖,99% 情況下無需同步,效能差。

3. 雙重檢查鎖(DCL,JDK 5+ 可用)⚡

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

volatile 禁止指令重排,確保其他線程見到完全初始化的物件。JDK 5 前 JMM 有缺陷,不可用。

4. 餓漢式(類載入即初始化)🚀

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

利用 ClassLoader 機制天然線程安全,無鎖高效。缺點:無法延遲載入,若建構子依賴外部配置則不適用。

5. 靜態內部類(延遲載入 + 線程安全 + 簡潔)✨ 推薦

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

外部類載入時不初始化 Holder,只有呼叫 getInstance() 才會觸發初始化,兼具 lazy loading 與高效能,不依賴 JDK 版本。

6. 列舉(防序列化破壞、防反射攻擊)🛡️ 最佳

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

Josh Bloch 大力推薦。序列化機制天然保證單一實例,反射無法破壞,程式碼最簡潔。

實戰選型指南

場景推薦方式理由
一般業務,無特殊需求靜態內部類簡潔、延遲載入、高效能
需防序列化/反射破壞列舉語言層面保證,最安全
建構子依賴外部參數/配置DCL 或靜態內部類+建構子參數支援延遲初始化並傳參
極簡原型/測試代碼餓漢式一行搞定,無負擔

常見誤區提醒

  • synchronized 加在方法上 vs 代碼塊:代碼塊粒度更細,效能更好。
  • 忘記 volatile 導致 DCL 失效(指令重排)。
  • 序列化/反序列化破壞單例:實作 readResolve() 或改用列舉。

總結

單例模式核心在於私有建構子 + 靜態工廠方法。實務上靜態內部類與列舉足以覆蓋 99% 場景,建議作為預設選擇;僅在極特殊需求下考慮 DCL。

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