亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

c#單例模式(Singleton)的6種實現

2020-01-24 00:52:16
字體:
來源:轉載
供稿:網友

1.1.1 摘要

 在我們日常的工作中經常需要在應用程序中保持一個唯一的實例,如:IO處理,數據庫操作等,由于這些對象都要占用重要的系統資源,所以我們必須限制這些實例的創建或始終使用一個公用的實例,這就是我們今天要介紹的――單例模式(Singleton)。

 使用頻率

單件模式(Singleton):保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。

1.1.2 正文

圖1單例模式(Singleton)結構圖

單例模式(Singleton)是幾個創建模式中最對立的一個,它的主要特點不是根據用戶程序調用生成一個新的實例,而是控制某個類型的實例唯一性,通過上圖我們知道它包含的角色只有一個,就是Singleton,它擁有一個私有構造函數,這確保用戶無法通過new直接實例它。除此之外,該模式中包含一個靜態私有成員變量instance與靜態公有方法Instance()。Instance()方法負責檢驗并實例化自己,然后存儲在靜態成員變量中,以確保只有一個實例被創建。

圖2單例模式(Singleton)邏輯模型

接下來我們將介紹6中不同的單例模式(Singleton)的實現方式。這些實現方式都有以下的共同點:

 1.有一個私有的無參構造函數,這可以防止其他類實例化它,而且單例類也不應該被繼承,如果單例類允許繼承那么每個子類都可以創建實例,這就違背了Singleton模式“唯一實例”的初衷。

2.單例類被定義為sealed,就像前面提到的該類不應該被繼承,所以為了保險起見可以把該類定義成不允許派生,但沒有要求一定要這樣定義。

3.一個靜態的變量用來保存單實例的引用。

4.一個公有的靜態方法用來獲取單實例的引用,如果實例為null即創建一個。

版本一線程不安全

 /// <summary>/// A simple singleton class implements./// </summary>public sealed class Singleton{  private static Singleton _instance = null;  /// <summary>  /// Prevents a default instance of the   /// <see cref="Singleton"/> class from being created.  /// </summary>  private Singleton()  {  }  /// <summary>  /// Gets the instance.  /// </summary>  public static Singleton Instance  {    get { return _instance ?? (_instance = new Singleton()); }  }}

 以上的實現方式適用于單線程環境,因為在多線程的環境下有可能得到Singleton類的多個實例。假如同時有兩個線程去判斷

(null == _singleton),并且得到的結果為真,那么兩個線程都會創建類Singleton的實例,這樣就違背了Singleton模式“唯一實例”的初衷。

 版本二線程安全

 /// <summary>/// A thread-safe singleton class./// </summary>public sealed class Singleton{  private static Singleton _instance = null;  private static readonly object SynObject = new object();  Singleton()  {  }  /// <summary>  /// Gets the instance.  /// </summary>  public static Singleton Instance  {    get    {      // Syn operation.      lock (SynObject)      {        return _instance ?? (_instance = new Singleton());      }    }  }}

以上方式的實現方式是線程安全的,首先我們創建了一個靜態只讀的進程輔助對象,由于lock是確保當一個線程位于代碼的臨界區時,另一個線程不能進入臨界區(同步操作)。如果其他線程試圖進入鎖定的代碼,則它將一直等待,直到該對象被釋放。從而確保在多線程下不會創建多個對象實例了。只是這種實現方式要進行同步操作,這將是影響系統性能的瓶頸和增加了額外的開銷。

 Double-Checked Locking

前面講到的線程安全的實現方式的問題是要進行同步操作,那么我們是否可以降低通過操作的次數呢?其實我們只需在同步操作之前,添加判斷該實例是否為null就可以降低通過操作的次數了,這樣是經典的Double-Checked Locking方法。

 /// <summary>/// Double-Checked Locking implements a thread-safe singleton class/// </summary>public sealed class Singleton{  private static Singleton _instance = null;  // Creates an syn object.  private static readonly object SynObject = new object();  Singleton()  {  }  public static Singleton Instance  {    get    {      // Double-Checked Locking      if (null == _instance)      {        lock (SynObject)        {          if (null == _instance)          {            _instance = new Singleton();          }        }      }      return _instance;    }  }}

 在介紹第四種實現方式之前,首先讓我們認識什么是,當字段被標記為beforefieldinit類型時,該字段初始化可以發生在任何時候任何字段被引用之前。這句話聽起了有點別扭,接下來讓我們通過具體的例子介紹。

 /// <summary>/// Defines a test class./// </summary>class Test{  public static string x = EchoAndReturn("In type initializer");  public static string EchoAndReturn(string s)  {    Console.WriteLine(s);    return s;  }}

上面我們定義了一個包含靜態字段和方法的類Test,但要注意我們并沒有定義靜態的構造函數。

圖3 Test類的IL代碼

class Test{  public static string x = EchoAndReturn("In type initializer");  // Defines a parameterless constructor.  static Test()  {  }  public static string EchoAndReturn(string s)  {    Console.WriteLine(s);    return s;  }}

上面我們給Test類添加一個靜態的構造函數。

圖4 Test類的IL代碼

通過上面Test類的IL代碼的區別我們發現,當Test類包含靜態字段,而且沒有定義靜態的構造函數時,該類會被標記為beforefieldinit。

現在也許有人會問:“被標記為beforefieldinit和沒有標記的有什么區別呢”?OK現在讓我們通過下面的具體例子看一下它們的區別吧!

 class Test{  public static string x = EchoAndReturn("In type initializer");  static Test()  {  }  public static string EchoAndReturn(string s)  {    Console.WriteLine(s);    return s;  }}class Driver{  public static void Main()  {    Console.WriteLine("Starting Main");    // Invoke a static method on Test    Test.EchoAndReturn("Echo!");    Console.WriteLine("After echo");    Console.ReadLine();    // The output result:    // Starting Main    // In type initializer    // Echo!    // After echo        }}

我相信大家都可以得到答案,如果在調用EchoAndReturn()方法之前,需要完成靜態成員的初始化,所以最終的輸出結果如下:

圖5輸出結果

 接著我們在Main()方法中添加string y = Test.x,如下:

public static void Main(){  Console.WriteLine("Starting Main");  // Invoke a static method on Test  Test.EchoAndReturn("Echo!");  Console.WriteLine("After echo");  //Reference a static field in Test  string y = Test.x;  //Use the value just to avoid compiler cleverness  if (y != null)  {    Console.WriteLine("After field access");  }  Console.ReadKey();  // The output result:  // In type initializer  // Starting Main  // Echo!  // After echo  // After field access}

圖6 輸出結果

通過上面的輸出結果,大家可以發現靜態字段的初始化跑到了靜態方法調用之前,Wo難以想象??!

最后我們在Test類中添加一個靜態構造函數如下:

 class Test{  public static string x = EchoAndReturn("In type initializer");  static Test()  {  }  public static string EchoAndReturn(string s)  {    Console.WriteLine(s);    return s;  }} 

圖7 輸出結果

理論上,type initializer應該發生在”Echo!”之后和”After echo”之前,但這里卻出現了不唯一的結果,只有當Test類包含靜態構造函數時,才能確保type initializer的初始化發生在”Echo!”之后和”After echo”之前。

所以說要確保type initializer發生在被字段引用時,我們應該給該類添加靜態構造函數。接下來讓我們介紹單例模式的靜態方式。

 靜態初始化

 

public sealed class Singleton{  private static readonly Singleton _instance = new Singleton();  // Explicit static constructor to tell C# compiler  // not to mark type as beforefieldinit  static Singleton()  {  }  /// <summary>  /// Prevents a default instance of the   /// <see cref="Singleton"/> class from being created.  /// </summary>  private Singleton()  {  }  /// <summary>  /// Gets the instance.  /// </summary>  public static Singleton Instance  {    get    {      return _instance;    }  }}

以上方式實現比之前介紹的方式都要簡單,但它確實是多線程環境下,C#實現的Singleton的一種方式。由于這種靜態初始化的方式是在自己的字段被引用時才會實例化。

 讓我們通過IL代碼來分析靜態初始化。

圖8靜態初始化IL代碼

首先這里沒有beforefieldinit的修飾符,由于我們添加了靜態構造函數當靜態字段被引用時才進行初始化,因此即便很多線程試圖引用_instance,也需要等靜態構造函數執行完并把靜態成員_instance實例化之后可以使用。

 延遲初始化

 /// <summary>/// Delaies initialization./// </summary>public sealed class Singleton{  private Singleton()  {  }  /// <summary>  /// Gets the instance.  /// </summary>  public static Singleton Instance { get { return Nested._instance; } }  private class Nested  {    // Explicit static constructor to tell C# compiler    // not to mark type as beforefieldinit    static Nested()    {    }    internal static readonly Singleton _instance = new Singleton();  }}

這里我們把初始化工作放到Nested類中的一個靜態成員來完成,這樣就實現了延遲初始化。

 Lazy<T> type

 /// <summary>/// .NET 4's Lazy<T> type/// </summary>public sealed class Singleton{  private static readonly Lazy<Singleton> lazy =    new Lazy<Singleton>(() => new Singleton());  public static Singleton Instance { get { return lazy.Value; } }  private Singleton()  {  }}

 這種方式的簡單和性能良好,而且還提供檢查是否已經創建實例的屬性IsValueCreated。

 具體例子

現在讓我們使用單例模式(Singleton)實現負載平衡器,首先我們定義一個服務器類,它包含服務器名和IP地址如下:

 /// <summary>/// Represents a server machine/// </summary>class Server{  // Gets or sets server name  public string Name { get; set; }  // Gets or sets server IP address  public string IP { get; set; }}

由于負載平衡器只提供一個對象實例供服務器使用,所以我們使用單例模式(Singleton)實現該負載平衡器。

 /// <summary>/// The 'Singleton' class/// </summary>sealed class LoadBalancer{  private static readonly LoadBalancer _instance =    new LoadBalancer();  // Type-safe generic list of servers  private List<Server> _servers;  private Random _random = new Random();  static LoadBalancer()  {  }  // Note: constructor is 'private'  private LoadBalancer()  {    // Load list of available servers    _servers = new List<Server>       {        new Server{ Name = "ServerI", IP = "192.168.0.108" },       new Server{ Name = "ServerII", IP = "192.168.0.109" },       new Server{ Name = "ServerIII", IP = "192.168.0.110" },       new Server{ Name = "ServerIV", IP = "192.168.0.111" },       new Server{ Name = "ServerV", IP = "192.168.0.112" },      };  }  /// <summary>  /// Gets the instance through static initialization.  /// </summary>  public static LoadBalancer Instance  {    get { return _instance; }  }  // Simple, but effective load balancer  public Server NextServer  {    get    {      int r = _random.Next(_servers.Count);      return _servers[r];    }  }}

 上面負載平衡器類LoadBalancer我們使用靜態初始化方式實現單例模式(Singleton)。

 static void Main(){  LoadBalancer b1 = LoadBalancer.Instance;  b1.GetHashCode();  LoadBalancer b2 = LoadBalancer.Instance;  LoadBalancer b3 = LoadBalancer.Instance;  LoadBalancer b4 = LoadBalancer.Instance;  // Confirm these are the same instance  if (b1 == b2 && b2 == b3 && b3 == b4)  {    Console.WriteLine("Same instance/n");  }  // Next, load balance 15 requests for a server  LoadBalancer balancer = LoadBalancer.Instance;  for (int i = 0; i < 15; i++)  {    string serverName = balancer.NextServer.Name;    Console.WriteLine("Dispatch request to: " + serverName);  }  Console.ReadKey();}

圖9 LoadBalancer輸出結果

 1.1.3 總結

單例模式的優點:

單例模式(Singleton)會控制其實例對象的數量,從而確保訪問對象的唯一性。

1.實例控制:單例模式防止其它對象對自己的實例化,確保所有的對象都訪問一個實例。

2.伸縮性:因為由類自己來控制實例化進程,類就在改變實例化進程上有相應的伸縮性。

 單例模式的缺點:

1.系統開銷。雖然這個系統開銷看起來很小,但是每次引用這個類實例的時候都要進行實例是否存在的檢查。這個問題可以通過靜態實例來解決。

2.開發混淆。當使用一個單例模式的對象的時候(特別是定義在類庫中的),開發人員必須要記住不能使用new關鍵字來實例化對象。因為開發者看不到在類庫中的源代碼,所以當他們發現不能實例化一個類的時候會很驚訝。

3.對象生命周期。單例模式沒有提出對象的銷毀。在提供內存管理的開發語言(比如,基于.NetFramework的語言)中,只有單例模式對象自己才能將對象實例銷毀,因為只有它擁有對實例的引用。在各種開發語言中,比如C++,其它類可以銷毀對象實例,但是這么做將導致單例類內部的指針指向不明。 

單例適用性

使用Singleton模式有一個必要條件:在一個系統要求一個類只有一個實例時才應當使用單例模式。反之,如果一個類可以有幾個實例共存,就不要使用單例模式。

不要使用單例模式存取全局變量。這違背了單例模式的用意,最好放到對應類的靜態成員中。

不要將數據庫連接做成單例,因為一個系統可能會與數據庫有多個連接,并且在有連接池的情況下,應當盡可能及時釋放連接。Singleton模式由于使用靜態成員存儲類實例,所以可能會造成資源無法及時釋放,帶來問題。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
精品动漫一区二区| 成人激情在线观看| 日韩在线不卡视频| 欧美专区在线播放| 欧美大片va欧美在线播放| 国产日韩欧美在线视频观看| 日韩av电影在线网| 成人激情视频在线播放| 成人欧美一区二区三区黑人孕妇| 国产精品福利在线| 成人性生交大片免费看小说| 中文字幕亚洲综合| 一区二区在线视频播放| 91精品视频免费观看| 国产精品久久一区主播| 98精品国产自产在线观看| 精品电影在线观看| 国产精品久久久久久久久粉嫩av| 国产99视频在线观看| 欧美成人午夜激情| 欧美精品电影免费在线观看| 久久在线精品视频| 欧美黄色成人网| 欧美极品少妇xxxxⅹ裸体艺术| 在线观看视频亚洲| 欧美国产极速在线| www.久久草.com| 在线视频欧美日韩精品| 欧美丝袜一区二区三区| 日韩中文字幕在线精品| 国产精品视频永久免费播放| 欧美性黄网官网| 亚洲风情亚aⅴ在线发布| 中文字幕九色91在线| 欧美性猛交xxxx乱大交蜜桃| 国产日韩av在线播放| 日韩精品在线观看一区| 久久视频免费观看| 狠狠色噜噜狠狠狠狠97| 亚洲精品日韩久久久| 亚洲自拍中文字幕| 欧美精品一区二区三区国产精品| 亚洲最大福利视频网站| 亚洲欧美在线看| 久久99国产精品自在自在app| 亚洲国产99精品国自产| 欧美精品videosex性欧美| 亚洲欧美制服另类日韩| 日韩精品视频在线播放| 欧美性开放视频| 亚洲精品电影在线观看| 亚洲黄色www网站| 日韩av中文字幕在线免费观看| 久久久精品影院| 97精品国产97久久久久久免费| 欧美性xxxx18| 国产精品丝袜视频| 亚洲最大的成人网| 久久久国产精品x99av| 色伦专区97中文字幕| 中文字幕在线成人| 欧美性色xo影院| 国产成人拍精品视频午夜网站| 久久精品欧美视频| 久久久精品在线观看| 亚洲a成v人在线观看| 亚洲最大福利视频网站| 亚洲国产精品网站| 亚洲欧美制服另类日韩| 久久久女人电视剧免费播放下载| 91麻豆国产语对白在线观看| 欧美激情2020午夜免费观看| 欧美成人sm免费视频| 日本精品久久电影| 91在线观看免费网站| 2018国产精品视频| 久久久久久97| 亚洲人成电影网| 久久久久久久国产精品视频| 尤物99国产成人精品视频| 亚洲激情在线观看视频免费| 精品国产区一区二区三区在线观看| 欧美一区二区三区艳史| 国产在线不卡精品| 亚洲国产另类 国产精品国产免费| 日韩中文字幕国产精品| 日韩欧美亚洲综合| 性色av一区二区三区红粉影视| 成人在线激情视频| 丝袜一区二区三区| 亚洲成年人影院在线| 97在线看免费观看视频在线观看| 91久久久久久久久| 久久久久久久97| 亚洲精品国产欧美| 精品欧美激情精品一区| 欧美日韩国产综合视频在线观看中文| 亚洲视频在线观看免费| 91香蕉亚洲精品| 日韩在线国产精品| 亚洲人成绝费网站色www| 少妇高潮 亚洲精品| 国产99久久精品一区二区| 国产视频欧美视频| 91人成网站www| 亚洲精品日韩丝袜精品| 国产精品福利久久久| 97激碰免费视频| 清纯唯美日韩制服另类| 伊人久久综合97精品| 成人免费看吃奶视频网站| 国产区精品在线观看| 91av免费观看91av精品在线| 国产精品wwwwww| 国产精品美女在线| 欧美另类在线观看| 久久成人一区二区| 自拍视频国产精品| 欧美视频二区36p| 欧美高清电影在线看| 日韩中文字幕在线免费观看| 少妇高潮 亚洲精品| 亚洲中国色老太| 国产精品扒开腿做| 国产做受69高潮| 亚洲欧美精品中文字幕在线| 国内免费久久久久久久久久久| 久久97久久97精品免视看| 国产一区视频在线| 久久精品国产欧美激情| 国产视频精品自拍| 欧美日韩精品国产| 伊人久久五月天| 欧美精品成人91久久久久久久| 国产女同一区二区| 欧美在线免费看| 色妞欧美日韩在线| 成年无码av片在线| 国产一区二区三区久久精品| 欧美日韩国产一区中文午夜| 欧美日韩在线视频一区二区| 国产精品欧美亚洲777777| 欧美高清第一页| 久久精品国产v日韩v亚洲| 亚洲成人激情小说| 欧美性猛交xxxx乱大交蜜桃| 97精品国产aⅴ7777| 九九久久精品一区| 国产成人综合精品| 成人福利视频网| 日韩在线视频一区| 91精品国产综合久久香蕉| 久久精品视频网站| 中文字幕精品www乱入免费视频| 日韩中文综合网| 国产精品一久久香蕉国产线看观看| 按摩亚洲人久久| 国内外成人免费激情在线视频| 日韩国产精品视频| 久久久久久尹人网香蕉| 欧美激情精品久久久久久变态| 国产美女久久精品| 国产精品亚洲美女av网站| 高清欧美电影在线|