前言
單例模式(Singleton),保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
通常我們可以讓一個全局變量使得一個對象被訪問,但它不能防止你實例化多個對象。一個最好的辦法就是,讓類自身負責保存它的唯一實例。這個類可以保證沒有其他實例可以被創建,並且它可以提供一個訪問該實例的方法。
單例模式
public class Singleton { private static Singleton instance; private static readonly object SyncRoot = new object(); ///程序運行時創建一個靜態的只讀對象 private Singleton(){} public static Singleton GetInstance() { ///雙重鎖定 先判斷實例是否存在,不存在再加鎖處理 ///這樣不用讓線程每次都加鎖,保證了線程安全,也提高了性能 if (instance == null) { lock (SyncRoot) ///在同一個程序加了鎖的那部分程序只有一個線程可以加入 {
///若實例不存在,則new一個新實例,否則返回已有的實例
if (instance == null) { instance = new Singleton(); } } } return instance; } }
說明:
構造方法private Singleton(){},讓其private,這樣就堵死了外界利用new創建此類實例的可能
public static Singleton GetInstance() 此方法是獲得本類實例的唯一全局訪問點
lock:是確保當一個線程位於代碼的臨界區時,另一個線程不進入臨界區。如果其他線程試圖進入鎖定的代碼,則它將一直等待(即被阻止),直到該對象被釋放。
然后在上面的Singleton類中添加一個測試方法
//類函數 public void Test() { Console.WriteLine("Hello World!"); }
最后即可在控制台應用程序的入口函數進行調用測試
class Program { static void Main(string[] args) { Singleton.GetInstance().Test(); Console.ReadLine(); } }
結果也Ok
Singleton s1 = Singleton.GetInstance(); Singleton s2 = Singleton.GetInstance(); if (s1 == s2) { Console.WriteLine("兩個對象是相同的實例"); }
繼續在Main函數中添加實例代碼,判斷兩個實例化對象是否為一個對象。
靜態初始化
其實咋實際應用當中,C#與公共語言運行庫也提供了一種“靜態初始化”方法,這種方法不需要開發人員顯示的編寫線程安全代碼,即可解決多線程環境下它是不安全的問題。
public sealed class Singletons { private static readonly Singletons instance = new Singletons(); private Singletons() { } public static Singletons GetInstance() { return instance; } }
通過sealed修飾符來修飾類,是阻止發生派生,而派生可能會增加實例
在第一次引用類的任何成員時創建實例。公共語言運行庫負責處理變量初始化。並通過readonly標記instance變量,這意味着只能在靜態初始化期間或在類構造函數中分配變量。由於這種靜態初始化的方式是在自己被加載時就將自己實例化,所以被形象的稱之為餓漢式單例類,上面的單例模式處理方式是要在第一次被引用時,才會將自己實例化,所以就被成為懶漢式單例類。
總結
餓漢式,即靜態初始化的方式,它是類一加載就實例化對象,所以要提前占用系統資源。然后懶漢式,又會面臨着多線程訪問的安全性問題,需要做雙重鎖定這樣的處理才可以保證安全。送一到底使用哪一種方式,取決於實際的需求。從C#語言的角度來講,餓漢式的單例類已經足夠滿足我們的需求了。