設計模式目錄:html
本篇目錄:java
單例模式(Singleton)能夠說是最簡單的模式,對.net來講,由於不須要考慮到垃圾回收機制,實現起來很簡單,可是對於沒有提供內存管理的平臺來講,好比C++,由於單例模式只考慮建立對象,因此使用的時候要考慮全面些。函數
其實說到些設計模式,咱們有時候用到的真的不多,就像飛機零部件的模具不適用於汽車製造同樣,某些設計模式也只在特定的環境下使用,單例模式的使用場景通常是資源管理器等,像說的最多的就是打印機場景:每臺計算機能夠有若干個打印機,但只能有一個Printer Spooler,以免兩個打印做業同時輸出到打印機中。每臺計算機能夠有若干傳真卡,可是隻應該有一個軟件負責管理傳真卡,以免出現兩份傳真做業同時傳到傳真卡中的狀況。每臺計算機能夠有若干通訊端口,系統應當集中管理這些通訊端口,以免一個通訊端口同時被兩個請求同時調用。說白點就是一個男人能夠有不少女友,可是結婚生子的只能是其中一個。一夫多妻的狀況就不是單例模式了,那應該是「多態」了。哈哈。post
單例模式(Singleton)在.net中的定義是:一個類有且僅有一個實例,而且自行實例化向整個系統提供。學習
從定義中咱們能夠看出,單例模式所具備的三個要點:測試
根據所說的要點,咱們能夠在.net中這樣簡單的實現:url
1 public class SingletonTest 2 { 3 public static SingletonTest model; 4 private SingletonTest() 5 { } 6 public static SingletonTest getSingleton() 7 { 8 if (model==null) 9 { 10 model = new SingletonTest(); 11 } 12 return model; 13 } 14 }
代碼就這麼簡單,在getSingleton()方法返回實例的時候要先判斷對象是否已經被實例化,若是是就不須要從新建立了。
上面的代碼看起來沒什麼問題,可是在多線程的狀況下就會出現問題,咱們來開幾個線程測試下:
1 public class SingletonTest 2 { 3 public static SingletonTest model; 4 private SingletonTest() 5 { } 6 public static SingletonTest getSingleton() 7 { 8 if (model==null) 9 { 10 Console.WriteLine(String.Format("我是被線程:{0}建立的!", Thread.CurrentThread.Name)); 11 model = new SingletonTest(); 12 } 13 return model; 14 } 15 }
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Program p1 = new Program(); 6 p1.Test(); 7 Console.ReadLine(); 8 } 9 10 private void Test() 11 { 12 Thread newThread; 13 ThreadStart ts = new ThreadStart(DoWork); 14 for (int counter = 1; counter < 6; counter++) 15 { 16 newThread = new Thread(ts); 17 newThread.Name = "蟋蟀" + counter; 18 newThread.Start(); 19 } 20 } 21 22 protected void DoWork() 23 { 24 //調用返回對象方法 25 SingletonTest.getSingleton(); 26 } 27 }
執行結果:
根據上圖的執行結果,會發現SingletonTest對象被實例化了2次,按照單例模式(Singleton)的特性:一個類只能有一個實例,那就不是單例模式了,爲何會實例化兩次呢?由於咱們的計算機執行速度很快,在某一個時間點,線程1在執行完if (model==null)這段代碼,還沒執行model = new SingletonTest(),線程2恰好執行判斷對象是否null,就是說線程1和線程2都會進入下面的if判斷體中實例化對象。
關於單例模式的線程安全問題,網上一找一大堆,在《漫談設計模式》這本書中,做者也提到了線程安全問題,java中是使用的是「Double-Check Locking」方法,還有序列化的問題,這邊先不考慮,其實在.net中解決線程安全的問題也很簡單,就是用lock鎖,咱們根據上面的代碼,再來修改下,而後作個測試:
1 public class SingletonTest 2 { 3 private static SingletonTest singleton; 4 private static readonly object syncObject = new object(); 5 /// <summary> 6 /// 構造函數必須是私有的 7 /// 這樣在外部便沒法使用 new 來建立該類的實例 8 /// </summary> 9 private SingletonTest() 10 { } 11 /// <summary> 12 /// 定義一個全局訪問點 13 /// 設置爲靜態方法 14 /// 則在類的外部便無需實例化就能夠調用該方法 15 /// </summary> 16 /// <returns></returns> 17 public static SingletonTest getSingleton() 18 { 19 //這裏能夠保證只實例化一次 20 //即在第一次調用時實例化 21 //之後調用便不會再實例化 22 //第一重 singleton == null 23 if (singleton == null) 24 { 25 lock (syncObject) 26 { 27 //第二重 singleton == null 28 if (singleton == null) 29 { 30 Console.WriteLine(String.Format("我是被線程:{0}建立的!", Thread.CurrentThread.Name)); 31 singleton = new SingletonTest(); 32 } 33 } 34 } 35 return singleton; 36 } 37 }
執行結果:
從上面的執行結果咱們就能夠看到,對象僅被實例化了一次,在某段代碼體中,只能有且只有一個線程訪問,加鎖的目的就比如:咱們去火車站售票大廳買票,由於買票的人太多,爲了緩解壓力,就多開了幾個售票窗口(線程),好比南京到徐州的G110次列車只有一張票,窗口A和窗口B的人同時都在買這一班次的票,這時候就要加鎖,否則就有可能會出現只有一張票,可是賣出去兩張。話題跑偏了,哈哈。
示例代碼下載:Singleton.rar
關於模式,再多說兩句,在某些狀況下,像上面所說的:模式能夠當作現實生活中的模具,有些產品(項目)是由一種模具(模式)生成出來的,好比杯子、瓶子等,有些產品(項目)是由多種模具(模式)生成出來,而後組合而成的,好比汽車、飛機等,是由成千上萬個零部件組合造成的。就是說學會模式後要會懂得組合,並且要「合適」的組合,這樣纔會作出一個完善的產品(項目)。
仍是那就話:騷年們,和小菜一塊兒整理學習吧,未完待續。。。