最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#設計模式之Singleton模式

 更新時間:2020年06月11日 16:47:30   作者:老胡寫代碼  
這篇文章主要介紹了C#設計模式中的Singleton模式相關知識,文中代碼非常詳細,供大家理解學習,感興趣的朋友可以了解下

前言

Singleton是二十三個設計模式中比較重要也比較經常使用的模式。但是這個模式雖然簡單,實現(xiàn)起來也會有一些小坑,讓我們一起來看看吧!

實現(xiàn)思路

首先我們看看這個設計模式的UML類圖。

很清晰的可以看到,有三點是需要我們在實現(xiàn)這個模式的時候注意的地方。

  • 私有化的構造器
  • 全局唯一的靜態(tài)實例
  • 能夠返回全局唯一靜態(tài)實例的靜態(tài)方法

其中,私有化構造器是防止外部用戶創(chuàng)建新的實例而靜態(tài)方法用于返回全局唯一的靜態(tài)實例供用戶使用。原理清楚了,接下來我們看看一些典型的實現(xiàn)方式和其中的暗坑。

實現(xiàn)方法

最簡單的實現(xiàn)方法

最簡單的實現(xiàn)方法自然就是按照UML類圖直接寫一個類,我們看看代碼。

 class Program
 {
  static void Main(string[] args)
  {
  	var single1 = Singleton.Instance;
   var single2 = Singleton.Instance;
   Console.WriteLine(object.ReferenceEquals(single1, single2));
   Console.ReadLine();
  }
 }

 class Singleton
 {
  private static Singleton _Instance = null;
  private Singleton()
  {
   Console.WriteLine("Created");
  }

  public static Singleton Instance
  {
   get
   {
    if (_Instance == null)
    {
     _Instance = new Singleton();
    }
    return _Instance;
   }
  }

  public void DumbMethod()
  {

  }
 }

這段代碼忠實的實現(xiàn)了UML類圖里面的一切,查看輸出結果,

證實了Singleton確實起了作用,多次調用僅僅產生了一個實例,似乎這么寫就可以實現(xiàn)這個模式了。但是,真的會那么簡單嗎?

如果多線程亂入?

現(xiàn)在我們給剛剛的例子加點調料,假設多個對實例的調用,并不是簡單的,彬彬有禮的順序關系,二是以多線程的方式調用,那么剛剛那種實現(xiàn)方法,還能從容應對嗎?讓我們試試。把Main函數(shù)里面的調用改成這樣。

	static void Main(string[] args)
  {
   int TOTAL = 10000;
   Task[] tasks = new Task[TOTAL];
   for (int i = 0; i < TOTAL; i++)
   {
    tasks[i] = Task.Factory.StartNew(() =>
    {
     Singleton.Instance.DumbMethod();
    });
   }
			Task.WaitAll(tasks);
   Console.ReadLine();
  }

通過Factory創(chuàng)造出1萬個Task,幾乎同時去請求這個單例,看看輸出。

咦,我們剛剛寫的Singleton模式失效了,這個類被創(chuàng)造了5次(這段代碼運行多次,這個數(shù)字不一定相同),一定是多線程搞的鬼,我們剛剛寫的代碼沒有辦法應對多線程,換句話說,是非線程安全的(thread-safe),那有沒有辦法來攻克這個難關呢?

線程安全的單例模式

Lock版本

提到線程安全,很多同學第一反應就是用lock,不錯,lock是個可行的辦法,讓我們試試。添加一個引用類型的對象作為lock對象,修改代碼如下(什么?你問我為什必須是引用類型的對象而不能是值類型的對象?因為lock的時候,如果對象是值類型,那么lock僅僅鎖住了它的一個副本,另外一個線程可以暢通無阻的再次lock,這樣lock就失去了阻塞線程的意義)

	private static object _SyncObj = new object();
  public static Singleton Instance
  {
   get
   {
    lock (_SyncObj)
    {
     if (_Instance == null)
     {
      _Instance = new Singleton();
     }
     return _Instance;
    }    
   }
  }

運行一下,輸出

只有一個實例創(chuàng)建,證明Lock起作用了,這個模式可行!不過有些不喜歡用Lock的同學可能要問,還有沒有其他辦法呢?答案是有的。

靜態(tài)構造器版本

回想一下,C#中的類靜態(tài)構造器,只會在這個類第一次被使用的時候調用一次,天然的線程安全,那我們試試不用Lock使用類靜態(tài)構造器?修改Singleton類如下:

 class Singleton
 {
  private static Singleton _Instance = null;
  private Singleton()
  {
   Console.WriteLine("Created");
  }

  static Singleton()
  {
   _Instance = new Singleton();
  }

  //private static object _SyncObj = new object();
  public static Singleton Instance
  {
   get { return _Instance; }
  }

  public void DumbMethod()
  {

  }
 }

去掉了Lock,添加了一個類靜態(tài)構造器,試一試。

完美!對于不喜歡用Lock(在這個例子中,實例只會創(chuàng)建一次但是之后的所有線程都要先排隊Lock再進入Critical code進行檢查,效率比較低下)的同學,類靜態(tài)構造器提供了一種很好的選擇。
不過俗話說,人心苦不足 , 我們總是追求卓越。這個版本比Lock版本似乎更好一點,那還有沒有更好的版本呢?有的。

Lazy版本

從net 4.0開始,C#開始支持延遲初始化,通過Lazy關鍵字,我們可以聲明某個對象為僅僅當?shù)谝淮问褂玫臅r候,再初始化,如果一直沒有調用,那就不初始化,省去了一部分不必要的開銷,提升了效率。如果你不熟悉Lazy或者想更多了解它,請參考。我們今天關注的重點在于,Lazy也是天生線程安全的,所以我們嘗試用它來實現(xiàn)Singleton模式?修改代碼如下:

 class Singleton
 {
  private static Lazy<Singleton> _Instance = new Lazy<Singleton>(() => new Singleton());
  private Singleton()
  {
   Console.WriteLine("Created");
  }

  public static Singleton Instance
  {
   get
   {
    return _Instance.Value;
   }
  }

  public void DumbMethod()
  {

  }
 }

輸出結果中可以看到,我們達到了想要的效果:

在上面的代碼中,私有變量_Instance現(xiàn)在是被聲明為延遲初始化,這樣不但天然實現(xiàn)了線程安全,同時在沒有調用Instance靜態(tài)方法的時候(也即沒有調用_Instance.Value),初始化不會發(fā)生,這樣就提高了效率。

總結

Singleton模式很常見,實現(xiàn)起來也很簡單,只是要小心線程安全。以上三種方法都可以實現(xiàn)線程安全的Singleton模式。如果net 版本在4.0之上,建議使用Lazy版本,畢竟對比Lock版本,Lazy版本可以免去實現(xiàn)手動Lock之苦,對比Static版本,又有延遲初始化的性能優(yōu)勢,何樂而不為呢?

以上就是C#設計模式之Singleton模式的詳細內容,更多關于C#中的Singleton模式的資料請關注腳本之家其它相關文章!

相關文章

  • 仿orm自動生成分頁SQL分享

    仿orm自動生成分頁SQL分享

    平時接觸的數(shù)據(jù)庫有sql2000-2008,Oracle,SQLite 。 分頁邏輯,Oracle和SQLite相對好寫,就SQL事多,Sql2000下只能用top,排序2次,而Sql2005+就可以使用ROW_NUMBER()分析函數(shù)了,據(jù)說Sql2012對分頁又有了改進
    2014-01-01
  • C#程序(含多個Dll)合并成一個Exe的簡單方法

    C#程序(含多個Dll)合并成一個Exe的簡單方法

    這篇文章主要為大家詳細介紹了C#程序(含多個Dll)合并成一個Exe的簡單方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • C#使用泛型方法實現(xiàn)操作不同數(shù)據(jù)類型的數(shù)組

    C#使用泛型方法實現(xiàn)操作不同數(shù)據(jù)類型的數(shù)組

    這篇文章主要為大家詳細介紹了C#如何使用一個泛型方法對不同類型的數(shù)組進行操作,文中的示例代碼講解詳細,感興趣的小伙伴可以學習一下
    2024-02-02
  • C#模擬MSN窗體抖動的實現(xiàn)代碼

    C#模擬MSN窗體抖動的實現(xiàn)代碼

    這篇文章主要介紹了C#模擬MSN窗體抖動的實現(xiàn)代碼,非常實用的一個功能,需要的朋友可以參考下
    2014-08-08
  • C#實現(xiàn)gRPC服務和調用示例詳解

    C#實現(xiàn)gRPC服務和調用示例詳解

    gRPC?是一種與語言無關的高性能遠程過程調用?(RPC)?框架,這篇文章主要為大家詳細介紹了C#如何實現(xiàn)gRPC服務和調用,需要的可以參考一下
    2024-01-01
  • WinForm中的登錄實現(xiàn)

    WinForm中的登錄實現(xiàn)

    在一般的C/S系統(tǒng)中,登錄功能基本上是必備功能,總結了三種C# Winform登錄功能的實現(xiàn)方法
    2012-11-11
  • 基于C#實現(xiàn)員工IC卡的讀寫功能

    基于C#實現(xiàn)員工IC卡的讀寫功能

    這篇文章主要為大家詳細介紹了C#如何實現(xiàn)讀寫員工IC卡的功能,文中的示例代碼講解詳細,對我們學習C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-01-01
  • C#基礎學習系列之Attribute和反射詳解

    C#基礎學習系列之Attribute和反射詳解

    大家在使用Attribute的時候大多需要用到反射,所以放在一起。下面這篇文章主要給大家介紹了關于C#基礎學習系列之Attribute和反射的相關資料,文中給出了詳細的示例代碼供大家參考學習,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-09-09
  • C#語言async?await之迭代器工作原理示例解析

    C#語言async?await之迭代器工作原理示例解析

    這篇文章主要為大家介紹了C#語言async?await之迭代器工作原理示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • c#基數(shù)排序Radix sort的實現(xiàn)方法

    c#基數(shù)排序Radix sort的實現(xiàn)方法

    這篇文章主要介紹了c#基數(shù)排序Radix sort的實現(xiàn)方法,有需要的朋友可以參考一下
    2014-01-01

最新評論

改则县| 苏州市| 永平县| 泗洪县| 正蓝旗| 上虞市| 嘉定区| 康乐县| 呼玛县| 满城县| 宁都县| 湘西| 邵武市| 罗田县| 长沙县| 江北区| 吴江市| 峡江县| 额敏县| 长葛市| 南丰县| 顺昌县| 荥经县| 浦北县| 紫阳县| 广西| 昭觉县| 张家口市| 托里县| 忻城县| 定州市| 满城县| 即墨市| 根河市| 北辰区| 祁连县| 茂名市| 宝山区| 额尔古纳市| 屏东市| 富裕县|