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

Java 單例模式四大寫法深度解析:從懶漢、餓漢到雙重檢查鎖與靜態內部類

     編輯:Java 相關知識

前言:單例模式的核心約束

單例模式確保類別在全域僅有一個實例,並提供全域存取點。實現關鍵只有兩點:私有化建構子(防外部 new)與 靜態方法/屬性提供唯一實例。本文詳細比較四種經典寫法並補充雙重檢查鎖(DCL)與靜態內部類兩種進階寫法。

四大基礎寫法比較

1. 懶漢式(Lazy Initialization)

需求時才建立,多執行緒下必須加同步,否則多執行緒同時進入 if (instance == null) 會產生多個實例。

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

缺點:synchronized 鎖住整個方法,效能差;高併發下成為瓶頸。

2. 餓漢式

類別載入時即建立實例,天然執行緒安全(JVM 類別載入機制保證)。

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

缺點:若實例建立耗時或資源重,且可能不被使用,造成資源浪費。

3. 靜態常量式(Effective Java 推薦)

本質同餓漢,利用 static final 語義保證唯一性。

public class StaticFinalSingleton {
    public static final StaticFinalSingleton INSTANCE = new StaticFinalSingleton();
    private StaticFinalSingleton() {}
}

4. 靜態內部類式

結合懶漢延遲載入與執行緒安全,利用 JVM 類別載入機制:外部類別載入時不載入內部類,只有呼叫 getInstance() 時才載入 Holder 並初始化 INSTANCE。

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

推薦程度:★★★★★ 兼具延遲載入、高效能、執行緒安全、程式碼簡潔。

進階寫法:雙重檢查鎖

試圖兼顧延遲載入與效能,但 JDK 1.5 前因指令重排序有缺陷,需加 volatile 修飾 instance。

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

多執行緒驗證實驗

public class SingletonTest {
    public static void main(String[] args) {
        // 啟動大量執行緒同時呼叫 getInstance()
        // 驗證所有執行緒拿到的引用是否指向同一物件
    }
}

實務應用場景

  • 配置檔讀取器(LoadProperties):全域唯一、避免重複 I/O。
  • 資料庫連線池、日誌管理器、快取管理器。
  • 常與工廠模式結合:工廠本身做成單例,統一管理物件建立。

總結建議

  1. 一般情況首選靜態內部類。
  2. 極度追求效能且確定會被使用,可用餓漢/靜態常量。
  3. 需延遲載入且環境為 JDK 1.5+,可用DCL + volatile。
  4. 嚴禁將建構子設為 public,違背單例初衷。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved