單例模式:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
構成:
1.私有的構造函數
2.私有靜態的實例
3.返回實例的靜態方法
public class Singleton { PRivate static Singleton uniqueInstance = new Singleton(); private Singleton() { Console.WriteLine("this is a new singleton"); } public static Singleton getInstance() { if (uniqueInstance == null) { return uniqueInstance; } return uniqueInstance; } }
這種叫做餓漢模式,實例在類加載時就創建了,缺點是如果實例如果消耗大量的資源而沒有使用就會造成浪費,另一種懶漢模式,實例在被使用時才創建,
public class Singleton { private static Singleton uniqueInstance; private Singleton() { Console.WriteLine("this is a new singleton"); } public static Singleton getInstance() { if (uniqueInstance == null) { return uniqueInstance = new Singleton(); } return uniqueInstance; } }
但是這不是線程安全的
例如
class Program { static void Main(string[] args) { while (true) { Thread t1 = new Thread(Test); t1.Start(); } } static void Test() { Singleton s = Singleton.getInstance(); } }
執行的結果有可能是這樣
程序創建了多個實例,這不是我們想要的結果,原因是某個線程if (uniqueInstance == null)語句執行后讓出了使用權,當它重新獲得CPU使用權的時候,可能別的CPU已經創建了實例,而它并不知道,繼續執行return uniqueInstance= new Singleton();導致出現多個實例。
因此,要為方法加鎖
public class Singleton { private static Singleton uniqueInstance; private Singleton() { Console.WriteLine("this is a new singleton"); } private static readonly object syncRoot = new object(); public static Singleton getInstance() { lock (syncRoot) { if (uniqueInstance == null) { return uniqueInstance = new Singleton(); } } return uniqueInstance; } }
但是這又帶來了一個問題,在實例已經創建完成了,但還是會有大量的線程卡在lock (syncRoot),它們都還會嘗試創建實例,這降低了性能
為此,還要為此方法創建另外一個驗證
public static Singleton getInstance() { if (uniqueInstance == null) { lock (syncRoot) { if (uniqueInstance == null) { return uniqueInstance = new Singleton(); } } } return uniqueInstance; }
此時,當實例已經創建完成之后,各線程不再訪問臨界區,提高了性能
單例模式和靜態類的比較
1.單例模式可以懶加載,靜態類執行更快(為什么?),即在不同條件下二者有不同的性能表現
2.單例可以繼承和override
3.單例易于模擬,利于測試
4.單例利于維護狀態信息
新聞熱點
疑難解答