//單例類: class Singleton { //私有化的構造函數 private Singleton() { Console.WriteLine("This is a SingleObject"); } //單一的實例 private static Singleton instance; //全局訪問點 public static Singleton GetInstance() { //若是實例爲空,則new一個新實例 if (instance == null) { instance = new Singleton(); Console.WriteLine("Create a new Instance"); } else { Console.WriteLine("Get a Instance"); } return instance; } } //測試類: class Program { static void Main(string[] args) { Singleton s1 = Singleton.GetInstance2(); Singleton s2 = Singleton.GetInstance2(); /* OUT: This is a SingleObject Create a new Instance Get a Instance */ } }
根據new關鍵字實例化單例的前後順序,可把單例模式分爲餓漢式單例、懶漢式單例:html
餓漢式:開始時就實例化instance設計模式
懶漢式:須要時才實例化instance安全
//餓漢式:開始時就實例化instance public class Singleton { private Singleton (){} private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } } //懶漢式:須要時才實例化instance //上一段代碼同爲懶漢式 public class Singleton { private Singleton (){} private static Singleton instance; public static Singleton getInstance() { if (instance == null) instance = new Singleton(); return instance; } }
在上述懶漢式單例中,若多個線程同時進行到if (instance == null)
,則所有檢測經過,也就會形成多線程下建立了多個實例,即 多線程不安全。所以須要對多線程下的單例模式進行調整,實現線程安全,方法是 lock機制:多線程
//餓漢式 + 線程安全 + 單鎖 class Singleton { private Singleton() {} private static Singleton instance; //靜態只讀對象用於輔助實現lock private static readonly object locker = new object(); public static Singleton GetInstance() { //lock機制:確保一個線程位於該臨界區時,其餘線程不可再進入,直至當前線程訪問完畢 lock (locker) { if (instance == null) instance = new Singleton(); } return instance; } }
雖然加了lock鎖實現了懶漢模式下的線程安全,但咱們不難發現一個問題:若已經存在instance實例,在執行Getinstance()時還有必要lock{}嗎?顯然不須要,lock的使用必然是消耗必定空間的,所以爲了節省lock的空間,採用更優解法:雙重鎖定(Double-Check-Locking):函數
//餓漢式 + 線程安全 + 雙鎖 class Singleton { private Singleton() {} private static Singleton instance; //靜態只讀對象用於輔助實現lock private static readonly object locker = new object(); public static Singleton GetInstance() { //首次檢驗:是否須要加鎖 if(instance == null) { //爲當前線程加鎖 lock (locker) { //再次檢驗:避免當前線程實例化instance後,下一個線程再次實例 if (instance == null) instance = new Singleton(); } return instance; } } }