一、單例模式是什么?
定義:確保一個類僅僅能產生一個實例,並且提供一個全局訪問點來獲取該實例。
二、單例模式怎么用?
1 class SingleCase 2 { 3 public string Name{get;set;} 4 public static SingleCase mySingle = null; 5 public static object Flag = new object(); 6 7 public static SingleCase getInstance(string name) 8 { 9 //判斷是否實例化過 10 if(mySingle == null) 11 { 12 //進入lock 13 lock(Flag) 14 { 15 //判斷是否實例化過 16 if(mySingle == null) 17 { 18 mySingle = new SingleCase(); 19 mySingle.Name = name 20 } 21 } 22 } 23 return mySingle; 24 } 25 }
其實本人語言組織能力差,不太擅長寫詳細解析。不過既然有園友提議說多寫寫解析,那就在下獻丑了。
單例模式的懶漢模式為什么用到兩個判斷一個鎖?
這就需要根據代碼一層一層來分析了(這些都是個人見解,不對的地方請諒解):
//其實如果只針對單線程而言,使用一個判斷就可以 if(mySingle == null) { mySingle = new SingleCase(); mySingle.Name = name } //但是遇到多線程時候上面的代碼就不能確保只產生一個實例了(這里多線程的概念就不做介紹了) //所以這時候為了能夠確保只產生一個實例,這里就使用了lock使線程同步(即同個時間段只允許一個線程執行) lock(Flag) { //判斷是否實例化過 if(mySingle == null) { mySingle = new SingleCase(); mySingle.Name = name } } //經過上述代碼應該就可以確保無論是單線程還是多線程都只能產生一個實例了, //那為什么在lock外面還需要再加一個判斷呢? //這里有個多線程性能問題:因為lock的功能是使一個線程(A)通過,而讓其他線程進入等待(A)線程執行完再執行。 //那么如何優化呢? //只要有一個線程產生了一個實例,那后續其他線程不再需要進入lock //所以這就是lock外面還需要再加一個判斷的原因 //判斷是否實例化過 if(mySingle == null) { //進入lock lock(Flag) { //判斷是否實例化過 if(mySingle == null) { mySingle = new SingleCase(); mySingle.Name = name } } }
三、為什么用單例模式?
對於系統中的某些類來說,只有一個實例很重要,例如,一個系統中可以存在多個打印任務,但是只能有一個正在工作的任務;一個系統只能有一個窗口管理器或文件系統;
一個系統只能有一個計時工具或ID(序號)生成器。如在Windows中就只能打開一個任務管理器。如果不使用機制對窗口對象進行唯一化,將彈出多個窗口,如果這些窗口顯示的內容完全一致,則是重復對象,浪費內存資源;
如果這些窗口顯示的內容不一致,則意味着在某一瞬間系統有多個狀態,與實際不符,也會給用戶帶來誤解,不知道哪一個才是真實的狀態。因此有時確保系統中某個對象的唯一性即一個類只能有一個實例非常重要。
如何保證一個類只有一個實例並且這個實例易於被訪問呢?定義一個全局變量可以確保對象隨時都可以被訪問,但不能防止我們實例化多個對象。一個更好的解決辦法是讓類自身負責保存它的唯一實例。
這個類可以保證沒有其他實例被創建,並且它可以提供一個訪問該實例的方法。這就是單例模式的模式動機。
四、使用場景
- Web應用的配置對象的讀取,一般也應用單例模式,這個是由於配置文件是共享的資源。
- 應用程序的日志應用,一般都何用單例模式實現,這一般是由於共享的日志文件一直處於打開狀態,因為只能有一個實例去操作,否則內容不好追加
