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

Java 單例模式深度解析:餓漢式與懶漢式實現對比

     編輯:關於C++

單例模式核心特點

單例模式確保一個類在整個 JVM 進程中只存在一個實例,並提供全局訪問點。適用於需要頻繁創建/銷毀、創建耗時較大或需要共享資源的場景(如線程池、緩存、配置管理器)。

實現三步走

  1. 私有化構造器:防止外部通過 new 創建實例。
  2. 內部持有自身實例:靜態成員變量引用唯一實例。
  3. 提供靜態獲取方法:對外暴露 getInstance() 返回該實例。

餓漢式 —— 類加載時即創建實例

public class SingletonEager {
    // 1. 私有構造器
    private SingletonEager() {}

    // 2. 類加載時立即創建實例(線程安全)
    private static final SingletonEager INSTANCE = new SingletonEager();

    // 3. 靜態工廠方法
    public static SingletonEager getInstance() {
        return INSTANCE;
    }
}

優點:實現簡單,由 JVM 類加載機制天然保證線程安全。
缺點:若實例從未被使用,會造成記憶體浪費;無法實現延遲加載。

懶漢式 —— 首次調用時才創建實例

public class SingletonLazy {
    private static SingletonLazy instance = null;

    private SingletonLazy() {}

    // 非線程安全版本
    public static SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
}

優點:延遲加載,按需創建。
缺點:多線程環境下會創建多個實例(線程不安全)。

線程安全的懶漢式改進

1. 同步方法(性能較差)

public static synchronized SingletonLazy getInstance() { ... }

2. 雙重檢查鎖(DCL,推薦)

public static SingletonLazy getInstance() {
    if (instance == null) {                    // 第一次檢查
        synchronized (SingletonLazy.class) {   // 加鎖
            if (instance == null) {            // 第二次檢查
                instance = new SingletonLazy();
            }
        }
    }
    return instance;
}

注意:instance 必須聲明為 volatile,防止指令重排導致對象未完全初始化即被其他線程看到。

3. 靜態內部類(推薦,最優雅)

public class SingletonHolder {
    private SingletonHolder() {}

    private static class Holder {
        static final SingletonHolder INSTANCE = new SingletonHolder();
    }

    public static SingletonHolder getInstance() {
        return Holder.INSTANCE;
    }
}

利用類加載機制同時實現延遲加載與線程安全,代碼簡潔高效。

運行原理圖解

單例模式運行原理

總結與選型建議

場景推薦實現
實例創建開銷小、必定會用到餓漢式
實例創建開銷大、可能不會用到靜態內部類 / DCL
需要序列化/反序列化保持單例實現 readResolve() 或使用枚舉
防止反射攻擊枚舉單例 enum Singleton { INSTANCE; }

實際開發中,靜態內部類與枚舉是最佳實踐,兼顧性能、線程安全與代碼簡潔性。

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