小菜學習設計模式(二)—單例(Singleton)模式

前言

設計模式目錄: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

後記

  關於模式,再多說兩句,在某些狀況下,像上面所說的:模式能夠當作現實生活中的模具,有些產品(項目)是由一種模具(模式)生成出來的,好比杯子、瓶子等,有些產品(項目)是由多種模具(模式)生成出來,而後組合而成的,好比汽車、飛機等,是由成千上萬個零部件組合造成的。就是說學會模式後要會懂得組合,並且要「合適」的組合,這樣纔會作出一個完善的產品(項目)。

  仍是那就話:騷年們,和小菜一塊兒整理學習吧,未完待續。。。

相關文章
相關標籤/搜索