剛才在看阿尋的博客”C#設計模式學習筆記-單例模式“時,發現了評論里有幾個人在問單例模式在多線程環境下為什么lazy模式要加兩個if進行判斷,評論中的一個哥們劍過不留痕,給他們寫了一個demo來告訴他們為什么。
我看了一下這個demo,確實說明了這個問題,但我認為不夠直觀,呵呵,於是我就稍微的改了一下。
這是劍過不留痕的demo
using System; using System.Threading; namespace SingletonPattern { class Program { static Thread[] threads; static void Main(string[] args) { int threadsCapacity; Console.WriteLine("請輸入開啟的線程數:"); string s; do { s = Console.ReadLine(); if (!int.TryParse(s, out threadsCapacity)) { Console.WriteLine("數字格式不正確,請輸入開啟的線程數:"); continue; } else if (1 > threadsCapacity) { Console.WriteLine("數字應不小於 1,請輸入開啟的線程數:"); continue; } else { break; } } while (true); threads = new Thread[threadsCapacity]; Program pg = new Program(); for (int i = 0; i < threads.Length; i++) { Thread thread = new Thread(new ThreadStart(Singleton.GetIns)); thread.Name = "線程 " + i; threads[i] = thread; } for (int i = 0; i < threads.Length; i++) { threads[i].Start(); } Console.ReadKey(); } } class Singleton { private static Singleton instance; private static object _lock = new object(); private static int instanceQuantity = 0; private Singleton() { } public static Singleton GetInstance() { if (instance == null) { // 掛起線程,確保所有的線程都執行到這並等待 Thread.Sleep(1000); lock (_lock) { //if (instance == null) //{ // instance = new Singleton(); // ++instanceQuantity; // Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 實例!"); //} instance = new Singleton(); ++instanceQuantity; Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 實例!"); } } return instance; } public static void GetIns() { GetInstance(); } } }
下面是我修改過得demo,修改的地方主要在GetInstance()這個方法內部,其他地方沒動,所以我只貼出修改代碼的地方,免得占空間!
public static Singleton GetInstance() { if (instance == null) { // 掛起線程,確保所有的線程都執行到這並等待 Console.WriteLine("我是" + Thread.CurrentThread.Name + " ,instance等於null,哦,對象還沒創建呢,看來我有機會哦!"); Thread.Sleep(1000); lock (_lock) { Console.WriteLine("我是" + Thread.CurrentThread.Name + " ,instance等於null,哈哈,我鎖,我是第一個到的!創建對象的任務就交給我了!"); if (instance == null) { instance = new Singleton(); ++instanceQuantity; Console.WriteLine("我是" + Thread.CurrentThread.Name + " ,哼哼,對象是我創建的!"); } else { Console.WriteLine("我是"+Thread.CurrentThread.Name + ",雖然我之前判斷instance等於null,但現在判斷的時候,卻不等null了,唉,還是被別人快了一步!不過好在我判斷了,要不就多創建了一個,失去了單例模式的意義!"); } //Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 實例!"); //instance = new Singleton(); //++instanceQuantity; //Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 實例!"); } } return instance; }
下面是運行的結果,多運行幾遍就可能出現這個結果了。

文字描述:
雖然線程0先進的第一個if,但創建對象的確實線程1,而此時,線程0已經判斷了instance==null,所以他還會再創建一個對象,因為並沒有人告訴線程0,線程1已經創建過對象了,而內部的這個if,就是為了告訴別人,對象我已經創建過了!其他人就不要再創建了,不知道我這樣解釋,清楚不!
