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

單例模式在 C# 中的實作詳解(上):基本模式與執行緒安全

     編輯:關於C語言

單例模式核心意圖

確保類別在應用程式生命週期內僅有一個實例,並提供全域存取點(非全域變數)。適用於:計數器、設定管理器、連線池、日誌記錄器等。

兩種經典實作

方法一:急切初始化

public sealed class Singleton {
    private static readonly Singleton instance = new Singleton();
    private Singleton() { }  // 私有建構子防止外部 new
    public static Singleton Instance { get { return instance; } }
}
  • 類別載入時即建立實例
  • 天生執行緒安全(CLR 保證靜態建構子原子性)
  • 缺點:即使未使用也佔用資源

方法二:延遲初始化

public sealed class Singleton {
    private static Singleton instance;
    private Singleton() { }
    public static Singleton Instance {
        get {
            if (instance == null)
                instance = new Singleton();  // 非執行緒安全!
            return instance;
        }
    }
}
  • 首次存取時才建立
  • 多執行緒競態條件:兩執行緒同時通過 null 檢查 → 建立兩個實例

多執行緒競態示範:計數器案例

public class Counter {
    private static Counter uniqueInstance;
    private int count = 0;
    private Counter() { Thread.Sleep(100); }  // 模擬初始化延遲
    public static Counter Instance {
        get {
            if (uniqueInstance == null)
                uniqueInstance = new Counter();
            return uniqueInstance;
        }
    }
    public void Increment() { count++; }
    public int Count { get { return count; } }
}

四個執行緒各遞增 4 次,預期 16。若無同步,可能出現計數歸零(重複初始化)。

三種同步解決方案

1. MethodImplOptions.Synchronized 屬性

[MethodImpl(MethodImplOptions.Synchronized)]
public static Counter Instance {
    get {
        if (uniqueInstance == null)
            uniqueInstance = new Counter();
        return uniqueInstance;
    }
}

鎖定整個方法(相當於 lock(this) 或 lock(typeof(Counter)))。

2. lock 關鍵字(推薦)

private static readonly object syncLock = new object();
public static Counter Instance {
    get {
        lock (syncLock) {
            if (uniqueInstance == null)
                uniqueInstance = new Counter();
            return uniqueInstance;
        }
    }
}
  • 鎖專用私有物件,避免公開型別被外部鎖定
  • 釋放鎖時隱含記憶體柵欄,保證可見性

3. Mutex 核心物件

private static Mutex mutex = new Mutex();
public static Counter Instance {
    get {
        mutex.WaitOne();
        try {
            if (uniqueInstance == null)
                uniqueInstance = new Counter();
            return uniqueInstance;
        } finally {
            mutex.ReleaseMutex();
        }
    }
}
  • 跨處理序同步(過重,單一程序用 lock 即可)
  • 需注意 AbandonedMutexException

雙重檢查鎖定(Double-Check Locking)

public static Counter Instance {
    get {
        if (uniqueInstance == null) {  // 第一次檢查:無鎖,效能佳
            lock (syncLock) {
                if (uniqueInstance == null)  // 第二次檢查:持鎖
                    uniqueInstance = new Counter();
            }
        }
        return uniqueInstance;
    }
}

注意:.NET 2.0+ 記憶體模型保證此模式正確(volatile 或隱含柵欄)。舊版需標記 volatile。

測試驗證

class Program {
    static void Main() {
        Thread[] threads = new Thread[4];
        for (int i = 0; i < 4; i++) {
            int id = i;
            threads[i] = new Thread(() => {
                for (int j = 0; j < 4; j++) {
                    Counter.Instance.Increment();
                    Console.WriteLine($"Thread {id}: Count = {Counter.Instance.Count}");
                }
            });
            threads[i].Name = $"Thread {i}";
            threads[i].Start();
        }
        foreach (var t in threads) t.Join();
        Console.WriteLine($"Final: {Counter.Instance.Count}");  // 應為 16
    }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved