單例模式:程序唯一。
阿新 • • 發佈:2021-09-30
單例模式:程序唯一。
-
非執行緒安全。
public sealed class SingletonV1 { private static SingletonV1 instance = null; private SingletonV1() { } public static SingletonV1 Instance { get { if (instance == null) // -> 1 { // -> 2 instance = new SingletonV1(); } return instance; } } }
假設:首次訪問,同一時間,有N(N>=2)個執行緒同時訪問單例。
解:
- 例項並未建立,所有執行緒都能進入建立例項程式碼塊。
- N個執行緒使用的例項不相同。
注:違反了單例的唯一性原則。
-
簡單執行緒安全。
public sealed class SingletonV2 { private static SingletonV2 instance = null; private static readonly object padlock = new object(); SingletonV2() { } public static SingletonV2 Instance { get { lock (padlock) // -> 1 { if (instance == null) { instance = new SingletonV2(); } return instance; } } } }
假設:同一時間,有N(N>=2)個執行緒同時訪問單例。
解:由於lock是悲觀鎖,導致獲取單例變成了單執行緒操作。
注:單執行緒的程式碼塊,會嚴重降低多執行緒的效能。
-
雙重檢查執行緒安全。
public sealed class SingletonV3 { private static SingletonV3 instance = null; private static readonly object padlock = new object(); SingletonV3() { } public static SingletonV3 Instance { get { if (instance == null) // -> 1 { lock (padlock) { if (instance == null) // -> 2 { instance = new SingletonV3(); } } } return instance; } } }
解:
- 第一層檢查的意義:當例項被建立後,不再進入鎖。
- 第二層檢查的意義:併發時,可能有多個執行緒躲過了第一層檢查,在鎖內部判斷,確保僅有一個執行緒建立例項。
注:只有例項未被建立之前的呼叫是單執行緒。
-
非懶惰執行緒安全。
public sealed class SingletonV4 { private static readonly SingletonV4 instance = new SingletonV4(); // -> 1 // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit static SingletonV4() { } private SingletonV4() { } public static SingletonV4 Instance { get { return instance; } } }
解:單例會在首次觸發靜態屬性/方法時,生成例項。
注:若類中存在靜態屬性/方法時,呼叫靜態屬性/方法也會建立例項,導致單例提前工作。
-
推薦完全懶惰執行緒安全。
public sealed class SingletonV5 { private SingletonV5() { } public static SingletonV5 Instance { get { return Nested.instance; } } // -> 1 private class Nested { // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit static Nested() { } internal static readonly SingletonV5 instance = new SingletonV5(); } }
注:僅在首次使用【SingletonV5.Instance】時,會建立例項。
-
懶載入執行緒安全。
public sealed class SingletonV6 { private static readonly Lazy<SingletonV6> lazy = new Lazy<SingletonV6>(() => new SingletonV6()); public static SingletonV6 Instance { get { return lazy.Value; } } private SingletonV6() { } }
注:使用懶載入,保證所有執行緒使用的例項相同,但並一定只會初始化一次例項。
引用:
-
強力推薦完全懶惰執行緒安全--反射。
public class SingletonV7<T> where T : class { static SingletonV7() { } public static T Instance => Nested.Instance; private static class Nested { static Nested() { } public static readonly T Instance = (T)Activator.CreateInstance(typeof(T), true); // -> 1 } }
解:
-
作為基類。
定義:繼承SingletonV7<T>,其中T是需要作為單例的類。
public sealed class Singleton : SingletonV7<Singleton> { private Singleton() { } public int Add(int i, int j) => i + j; }
用法:
int value = Singleton.Instance.Add(1, 2);
-
作為工具類。
定義:任意包含(公共/私有)無參建構函式的類。
public sealed class Singleton { private Singleton() { } public int Add(int i, int j) => i + j; }
用法:
int value = Singleton.Instance.Add(1, 2);
-