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

單例模式五種寫法深度對比:從懶漢到枚舉,線程安全與性能權衡

     編輯:Java 綜合教學

單例模式五種寫法深度對比:從懶漢到枚舉,線程安全與性能權衡

單例模式是面試必考、生產常用的創建型模式。本文系統分析五種經典實現的優缺點、適用場景與 JDK 版本依賴。

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

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

缺點:多線程並發可能創建多個實例。

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

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

缺點:鎖粒度過大,實例創建後每次調用仍同步,性能差。

3. 餓漢式(類載入即初始化,線程安全、非懶加載)

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

優點:JVM 保證類初始化線程安全,無同步開銷。
缺點:無法實現懶加載;若構造器依賴外部配置/參數則不適用。

4. 雙重檢查鎖 + 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;
    }
}

關鍵點:
① volatile 禁止指令重排序,確保 new Singleton() (分配內存→初始化→賦值引用) 可見性。
② JDK 1.5+ 修復了 volatile 語義,之前版本不可靠。
③ 現代 JVM 對未鎖定讀取優化極好,性能接近餓漢式。

5. 靜態內部類(IoDH,懶加載、線程安全、代碼簡潔)

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

原理:
① 外部類載入不初始化內部類。
① 調用 getInstance() 觸發 Holder 類初始化,JVM 保證 <clinit> 線程安全 (JLS §12.4.2)。
③ 兼具懶加載與零同步開銷,推薦生產環境使用。

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

public enum Singleton { INSTANCE; }

優勢:
① 天然線程安全、防反射攻擊 (構造器私有)、防序列化重複實例化。
② 代碼最簡潔,語義明確。
③ 缺點:無法懶加載、無法繼承、無法實現帶參構造。

對比總結表

寫法懶加載線程安全性能防反射/序列化推薦場景
懶漢(無鎖)是否高否單線程/教學
懶漢(synchronized)是是低否低併發/舊JDK
餓漢否是高否啟動即需實例、配置簡單
DCL+volatile是是(JDK5+)高否高併發、需懶加載
靜態內部類是是高否通用首選
枚舉否是高是安全要求極高、無懶加載需求

細節補充

  • static final 初始化順序:靜態字段按聲明順序 → 靜態代碼塊按順序,均在類初始化階段 (<clinit>) 執行。
  • 靜態內部類單例若需參數,可改用 Supplier 延遲初始化或 Builder 模式。
  • 反射破壞單例:Constructor.setAccessible(true) 可調用私有構造器,枚舉類無此漏洞。
  • 序列化破壞:實現 readResolve() 返回唯一實例可修復。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved