【轉】[C#] 單例模式

來自:阿里的 通義靈碼

在C#中,單例模式實現線程安全時通常會採用雙重檢查鎖定(Double-Checked Locking, DCL)的策略來確保只創建類的一個實例,並且這個過程是線程安全的。

兩層lock的設計是爲了減少獲取鎖的開銷,尤其是當類的實例已經被初始化的情況下。

以下是一個使用雙重檢查鎖定的C#單例模式示例:

public sealed class Singleton
{
    // 創建一個靜態變量來保存唯一的 Singleton 實例。
    private static volatile Singleton instance;
    // 創建一個對象用於同步訪問Singleton實例。
    private static object syncRoot = new Object();

    // 私有構造函數防止其他代碼通過new關鍵字實例化。
    private Singleton() {}

    // 提供一個公共的靜態方法來返回 Singleton 實例。
    public static Singleton Instance
    {
        get
        {
            // 第一層檢查:如果實例已存在,則直接返回,無需加鎖。
            if (instance != null)
            {
                return instance;
            }

            // 第二層檢查:只有當第一次進入這裏,即實例未被初始化時才需要加鎖。
            lock (syncRoot)
            {
                // 在鎖內再次檢查實例是否已被另一個線程初始化。
                // 這是因爲,在第一個if判斷和進入lock之間可能存在競態條件。
                if (instance == null)
                {
                    // 只有在這裏創建實例。
                    instance = new Singleton();
                }
                return instance;
            }
        }
    }
}

爲什麼需要兩層檢查?

  1. 性能優化
    • 第一次檢查instance != null可以在不加鎖的情況下完成,如果實例已經初始化,那麼大多數情況下可以直接返回實例,避免了不必要的鎖操作帶來的性能損耗。
  2. 線程安全性
    • 如果多個線程同時發現實例尚未創建,而只有一個線程能夠進入內部的lock塊進行初始化。如果沒有第二次檢查,所有線程都會創建實例,導致違反單例原則。
    • 由於CLR的內存模型允許對象的構造和初始化順序與指令執行順序不同步,因此即使在多線程環境中,也需要在lock保護下進行實例化以保證線程安全。第二層檢查確保了實例化操作僅執行一次。

總結來說,雙重檢查鎖定的目的在於既保證了線程安全,又儘量減少了對鎖的使用頻率,從而提高了程序的併發性能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章