單例模式 (Singleton),保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
通常我們可以讓一個全局變量使得一個對象被訪問,但它不能防止你實例化對個對象,一個最好的辦法就是,讓類自身負責保護它的唯一實例。這個類可以保證沒有其他實例可以被創建。并且它可以提供一個訪問該實例的方法。
Singleton類,定義一個GetInstance操作,允許客戶訪問它的唯一實例。GetInstance是一個靜態方法,主要是負責創建自己的唯一實例。
class Singleton
{private static Singleton instance;//構造方法讓其private 這就堵死了外界利用new創建此類實例的可能private Singleton(){}//此方法是獲得本類實例的唯一全局訪問點public static Singleton GetInstance(){if (instance == null) //若實例不存在,則New一個新實例,否則返回已有的實例{instance = new Singleton();}return instance;}
}
客戶端代碼:
static void Main(string[] args){Singleton s1 = Singleton.GetInstance();Singleton s2 = Singleton.GetInstance();if (s1 == s2) //比較兩次實例化后對象的結果是實例相同的{Console.WriteLine("兩個對象是相同的實例");}Console.ReadKey();}
單例模式的好處:
1、可以保證唯一的實例。
2、可以嚴格地控制客戶怎樣訪問它以及何時訪問它。簡單地說就是對唯一實例的受控訪問。
單例模式與實用類的靜態方法區別:
1、實用類不保存狀態,僅提供一些靜態方法或靜態屬性讓你使用。
單例雖然實例唯一,卻是可以有子類來繼承。
2、實用類是一些方法屬性的集合,單例是有著唯一的對象實例。
二、多線程時的單例
在多線程程序中,注意是同時訪問Singleton類,調用GetInstance()方法,會可能造成創建多個實例的。這個時候可以給進程加一把鎖來處理。
lock語句: lock是確保當一個線程位于代碼的臨界區時,另一個線程不進入臨界區,如果其他線程試圖進入鎖定的代碼,則它已知等待(即被阻止),指導該對象被釋放。
class Singleton{private static Singleton instance;//程序運行時創建一個靜態只讀的進程輔助對象private static readonly object syncRoot = new object();//構造方法讓其private 這就堵死了外界利用new創建此類實例的可能private Singleton(){}//此方法是獲得本類實例的唯一全局訪問點public static Singleton GetInstance(){lock (syncRoot)//在同一時刻加了鎖的那部分程序只有一個線程可以進入{if (instance == null) //若實例不存在,則New一個新實例,否則返回已有的實例{instance = new Singleton();}}return instance;}
}
這段代碼使得對象實例由最先進入的那個線程創建,以后的線程在進入時不再去創建對象實例了。由于有了lock,就保證了多線程環境下的同時訪問也不會造成多個實例的生產。
三、雙重鎖定
如果上面每次調用GetInstance方法時都需要lock,這樣做法會影響性能,所以可以雙重鎖定。
public static Singleton GetInstance(){//先判斷實例是否存在,不存在在加鎖.if (instance == null){lock (syncRoot){if (instance == null){instance = new Singleton();}}}return instance;}
現在這樣,我們不用讓線程每次都加鎖了,而只是在實例未被創建的時候再加鎖處理。同時也保證多線程的安全。這種做法被稱為Double-Check Locking(雙重鎖定)。