定義:確保一個類只有一個實例,並提供一個全局訪問點來訪問這個實例html
簡單的說,就是你有且只有一個女友(有多個女友的模式不是這裏~~),而且你的女友很特殊,歷來只聽你的話,因此別人想和她交流(訪問她)就必須經過你(全局訪問點)來和她交流。多線程
系統中用到單例模式的地方不少,好比Windows系統點擊開始只能出現一個開始界面,Ctrl+Alt+. 只能出現一個資源管理器,每一個進程有且對應惟一一個進程ID等等。單例模式是爲了讓資源獲得最大化利用,不浪費資源。同時假如不採用此模式,就可能在不一樣時刻打開同一個界面,但界面中的內容又各不相同,於是用戶極易產生誤解,影響使用效率。所以單例模式在系統中的應用很是重要。併發
要點:a.某一個單例類只能有一個實例;函數
b.必須自行建立這個實例;高併發
c.必須向系統提供這個實例;性能
結構: spa
實現:線程
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace Singleton 7 { 8 class Singleton 9 { 10 private static Singleton instance = null;//靜態私有成員變量 11 12 //私有構造函數 13 private Singleton() 14 { 15 Console.WriteLine("恭喜你,得到一個女友~~"); 16 } 17 18 //靜態公有方法,返回實例 19 public static Singleton Getinstance() 20 { 21 if(instance == null)//沒女友 22 instance = new Singleton();//生成一個吧 23 return instance;//有就返回當前的, 24 } 25 } 26 class Program 27 { 28 static void Main(string[] args) 29 { 30 Singleton s1 = Singleton.Getinstance(); 31 Singleton s2 = Singleton.Getinstance(); 32 if (s1 == s2) 33 { 34 Console.WriteLine("怎麼能想要共有一個女友呢?S2 趕忙換一個吧..."); 35 } 36 } 37 } 38 }
結果:設計
剛看到這兩個單例的名字時仍是有點可笑的,如此這麼生動形象呢,就好像餓漢式單身(連溫飽都知足不了,何來女友呢),懶漢式(好吃懶作的,也很難...)不亂扯了,回主題。餓漢式單例正如餓漢同樣,很餓很餓的人最想要的就是當即立刻吃東西。所以餓漢式單例在定義靜態變量時就實例化了單例類,由於實在太餓了啊,等不及了。code
1 class EagetSingleton 2 { 3 private static EagetSingleton instance = new EagetSingleton();//靜態變量實例化單例類 4 5 private EagetSingleton(){} 6 7 public static EagetSingleton GetInstance() 8 { 9 return instance; 10 } 11 }
懶漢式單例類則是在類第一次被引用時將本身實例化,單例類被加載時不會實例化,因此這很符合懶漢的氣質~可是在這裏要注意的是,在定義靜態變量時沒有實例化單例類,而是在第一次調用靜態方法時實例化單例類,這就會產生問題,高併發,多線程實現懶漢式單例時會建立多個對象,從而違背了單例模式的設計意圖。也就是仍是要對女友的個數進行判斷。這要怎麼辦呢?在多線程的狀況下,就要對該代碼段進行控制,即每次只讓一個線程進入並建立實例,也就是至關於如今的「共享女朋友」,幫你拍照啊,陪你去看電影啊 ,巴拉巴拉。可是,該「共享女朋友」有且只有一個,即單例類的惟一實例。因此,土豪們(各個線程)得一個一個租用,上一個用完了下一個才能租用。所以代碼以下:
1 class LazytSingleton 2 { 3 private static LazytSingleton instance = null; 4 private static readonly object synRoot = new object();//看作一個門。 5 //程序運行時建立只讀輔助對象 6 7 private LazytSingleton(){} 8 9 public static LazytSingleton GetInstance() 10 { 11 if(instance == null)//在房間外問:房間裏有人嗎 ? 沒人迴應 ,可能沒,可能下一秒有人進去 ,我卻覺得沒人 12 { 13 lock(synRoot)//第二次判斷 //把門關了,外面線程進不來,只能裏面的出來,外面的才能進 14 { 15 if(instance == null)//繼續問,房間裏有人嗎? 有就真的有,沒有就真的沒 16 { 17 instance = new LazytSingleton();//建立實例 18 } 19 } 20 } 21 } 22 }
兩者比較:
優勢:無需考慮多線程同時訪問的問題,確保實例惟一性。調用速度和反應時間快於懶漢模式,由於餓漢一開始就建立,後面則直接拿來用就能夠了。
缺點:無論單例對象是否須要,都會在類加載時建立,這樣不如懶漢式單例,資源利用不高,且加載時間較長。如啓動VS,Eclipse等,須要loading許多可能要的可能不要的,要等啊...
優勢:第一次使用時建立,不會一直佔用資源,即延遲加載。
缺點:必須考慮多線程問題,特別是單例類做爲資源控制器時,會涉及資源初始化,也會耗費許多時間,也會出現多線程同時首次引用此類,形成擁堵,致使系能性能下降