日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

设计模式之一:单例模式(Singleton Pattern)

發(fā)布時(shí)間:2025/7/14 asp.net 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 设计模式之一:单例模式(Singleton Pattern) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

寫(xiě)這個(gè)系列的文章,只為把所學(xué)的設(shè)計(jì)模式再系統(tǒng)的整理一遍。錯(cuò)誤和不周到的地方歡迎大家批評(píng)。點(diǎn)擊這里下載源代碼。

什么時(shí)候使用單例模式

在程序運(yùn)行時(shí),某種類(lèi)型只需要一個(gè)實(shí)例時(shí),一般采用單例模式。為什么需要一個(gè)實(shí)例?第一,性能,第二,保持代碼簡(jiǎn)潔,比如程序中通過(guò)某個(gè)配置類(lèi)A讀取配置文件,如果在每處使用的地方都new A(),才能讀取配置項(xiàng),一個(gè)是浪費(fèi)系統(tǒng)資源(參考.NET垃圾回收機(jī)制),再者重復(fù)代碼太多。

單例模式的實(shí)現(xiàn)

實(shí)現(xiàn)單例模式,方法非常多,這里我把見(jiàn)過(guò)的方式都過(guò)一遍,來(lái)體會(huì)如何在支持并發(fā)訪(fǎng)問(wèn)、性能、代碼簡(jiǎn)潔程度等方面不斷追求極致。(單擊此處下載代碼)

實(shí)現(xiàn)1:非線(xiàn)程安全

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading; 6: using System.Threading.Tasks; 7:? 8: namespace SingletonPatternNotTheadSafe 9: { 10: public sealed class Singleton 11: { 12: private static Singleton instance = null; 13:? 14: private Singleton() 15: { 16: } 17:? 18: public static Singleton Instance 19: { 20: get 21: { 22: if (instance == null) 23: { 24: Thread.Sleep(1000); 25: instance = new Singleton(); 26: Console.WriteLine(string.Format( 27: "[{0}]創(chuàng)建Singleton {1}" , Thread.CurrentThread.ManagedThreadId, instance.GetHashCode())); 28: } 29:? 30: Console.WriteLine(string.Format( 31: "[{0}]獲得Singleton {1}", Thread.CurrentThread.ManagedThreadId, instance.GetHashCode())); 32: return instance; 33: } 34: } 35: } 36: }

為了能夠在下面的測(cè)試代碼中展示上面代碼的問(wèn)題,這里在創(chuàng)建對(duì)象前,讓線(xiàn)程休息1秒,并且在控制臺(tái)打印出當(dāng)前線(xiàn)程ID、對(duì)象的hashcode(一般不同對(duì)象的hashcode是不一樣的,但可能重復(fù))。

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading; 6: using System.Threading.Tasks; 7:? 8: namespace SingletonPatternNotTheadSafe 9: { 10: class Program 11: { 12: private static void Main(string[] args) 13: { 14: Thread t1 = new Thread(new ThreadStart(Compute)); 15:? 16: t1.Start(); 17:? 18: Compute(); 19:? 20: Console.ReadLine(); // 阻止主線(xiàn)程結(jié)束 21: } 22:? 23: private static void Compute() 24: { 25: Singleton o1 = Singleton.Instance; 26: } 27: } 28: }

執(zhí)行結(jié)果如下:

分析:

Singleton.Instance的get方法中創(chuàng)建instance并未考慮并發(fā)訪(fǎng)問(wèn)的情況,導(dǎo)致可能重復(fù)創(chuàng)建Singleton對(duì)象。下面的實(shí)現(xiàn)方法修復(fù)了此問(wèn)題。

實(shí)現(xiàn)2:簡(jiǎn)單線(xiàn)程安全

要解決上面的問(wèn)題,最簡(jiǎn)單的方法就是在創(chuàng)建對(duì)象的時(shí)候加鎖。

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading; 6: using System.Threading.Tasks; 7:? 8: namespace SingletonSimpleThreadSafe 9: { 10: public sealed class Singleton 11: { 12: private static Singleton instance = null; 13: private static readonly object _lock = new object(); 14:? 15: private Singleton() 16: { 17: } 18:? 19: public static Singleton Instance 20: { 21: get 22: { 23: lock (_lock) 24: { 25: if (instance == null) 26: { 27: Thread.Sleep(1000); 28: instance = new Singleton(); 29: Console.WriteLine(string.Format( 30: "[{0}]創(chuàng)建Singleton {1}", Thread.CurrentThread.ManagedThreadId, instance.GetHashCode())); 31: } 32: } 33:? 34: Console.WriteLine(string.Format( 35: "[{0}]獲得Singleton {1}", Thread.CurrentThread.ManagedThreadId, instance.GetHashCode())); 36: return instance; 37: } 38: } 39: } 40: }

測(cè)試代碼如下:

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading; 6: using System.Diagnostics; 7: using System.Threading.Tasks; 8:? 9: namespace SingletonSimpleThreadSafe 10: { 11: class Program 12: { 13: private static void Main(string[] args) 14: { 15: SingletonTest(); 16: } 17:? 18: private static void SingletonTest() 19: { 20: Thread t1 = new Thread(new ThreadStart(Compute)); 21:? 22: t1.Start(); 23:? 24: Compute(); 25:? 26: Console.ReadLine(); // 阻止主線(xiàn)程結(jié)束 27: } 28:? 29: private static void Compute() 30: { 31: Singleton o1 = Singleton.Instance; 32: } 33: } 34: }

我們?cè)倏纯磮?zhí)行效果:

創(chuàng)建Singleton只執(zhí)行一次。但是這種寫(xiě)法性能并不高,每次通過(guò)Singleton.Instance獲得實(shí)例對(duì)象都需要判斷鎖是否別別的線(xiàn)程占用。

這里我們修改一下Singleton,把代碼中的Thread.Sleep和Console.Writeline都去掉,這里我重新創(chuàng)建了一個(gè)Singleton2 class,兩個(gè)線(xiàn)程中循環(huán)調(diào)用100000000次,看一下這么實(shí)現(xiàn)的性能:

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading; 6: using System.Threading.Tasks; 7:? 8: namespace SingletonSimpleThreadSafe 9: { 10: public sealed class Singleton2 11: { 12: private static Singleton2 instance = null; 13: private static readonly object _lock = new object(); 14:? 15: private Singleton2() 16: { 17: } 18:? 19: public static Singleton2 Instance 20: { 21: get 22: { 23: lock (_lock) 24: { 25: if (instance == null) 26: { 27: instance = new Singleton2(); 28: } 29: } 30:? 31: return instance; 32: } 33: } 34: } 35: }

測(cè)試代碼如下:

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading; 6: using System.Diagnostics; 7: using System.Threading.Tasks; 8:? 9: namespace SingletonSimpleThreadSafe 10: { 11: class Program 12: { 13: private static void Main(string[] args) 14: { 15: Singleton2Test(); 16: } 17:? 18: private static void Singleton2Test() 19: { 20: Thread t1 = new Thread(new ThreadStart(Compute2)); 21:? 22: t1.Start(); 23:? 24: Compute2(); 25:? 26: Console.ReadLine(); // 阻止主線(xiàn)程結(jié)束 27: } 28:? 29: private static void Compute2() 30: { 31: Stopwatch sw1 = new Stopwatch(); 32:? 33: sw1.Start(); 34:? 35: for (int i = 0; i < 100000000; i++) 36: { 37: Singleton2 instance = Singleton2.Instance; 38: } 39:? 40: sw1.Stop(); 41:? 42: Console.WriteLine(string.Format("[{0}]耗時(shí):{1}毫秒", 43: Thread.CurrentThread.ManagedThreadId, 44: sw1.ElapsedMilliseconds)); 45: } 46: } 47: }

執(zhí)行結(jié)果:

我們先不討論結(jié)果,接著往下看看雙檢鎖方式的性能。

實(shí)現(xiàn)3:雙檢鎖實(shí)現(xiàn)的線(xiàn)程安全

Singleton雙檢鎖實(shí)現(xiàn):

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading; 6: using System.Threading.Tasks; 7:? 8: namespace SingletonDoubleCheckThreadSafe 9: { 10: public sealed class Singleton2 11: { 12: private static Singleton2 instance = null; 13: private static readonly object _lock = new object(); 14:? 15: private Singleton2() 16: { 17: } 18:? 19: public static Singleton2 Instance 20: { 21: get 22: { 23: if (instance == null) 24: { 25: lock (_lock) 26: { 27: if (instance == null) 28: { 29: instance = new Singleton2(); 30: } 31: } 32: } 33:? 34: return instance; 35: } 36: } 37: } 38: }

測(cè)試代碼和上面的一樣,結(jié)果如下:

性能提高了(7571+7465-1410-1412)/ (7571+7465) * 100% = 81.2%。(實(shí)際項(xiàng)目中為了減少誤差,應(yīng)該跑多遍測(cè)試得到多個(gè)結(jié)果的平均值和方差,這里為了方便,我只把一次測(cè)試結(jié)果貼出來(lái)。

雙檢鎖機(jī)制在lock外又檢查了一次instance是否為null,這樣在第一次訪(fǎng)問(wèn)使instance創(chuàng)建后,后面的調(diào)用都無(wú)需檢查lock是否被占用。

一名程序員要了解到這里算基本合格,如果想達(dá)到更高的水平,繼續(xù)往下看。這種方式有什么缺點(diǎn)呢?

  • 上面的代碼在Java中不能正常工作。這是因?yàn)镴ava的Memory Model實(shí)現(xiàn)和.NET不一樣,并不保證一定在構(gòu)造函數(shù)執(zhí)行完成后才返回對(duì)象的引用。雖然Java 1.5版本重構(gòu)了Memory Model,但是雙檢鎖機(jī)制在不給instance field加volatile關(guān)鍵字時(shí),依然不能正常工作。
  • Microsoft的.net memory model并不是按照標(biāo)準(zhǔn)的ECMA CLI規(guī)范實(shí)現(xiàn),而是在標(biāo)準(zhǔn)上做了一些“增強(qiáng)”工作。MS .net CLR memory model中所有的寫(xiě)操作都是VolatileWrite(參考《CLR via C#》第二版的第24章)。所以我們的代碼中不加volatile也能在IA64CPU 架構(gòu)的機(jī)器上正常執(zhí)行。但是如Jeffrey建議,最好還是遵循ECMA標(biāo)準(zhǔn)。
  • 實(shí)現(xiàn)復(fù)雜。

實(shí)現(xiàn)4:非懶加載,無(wú)鎖實(shí)現(xiàn)線(xiàn)程安全

.NET中的static變量在class被第一次實(shí)例化的時(shí)候創(chuàng)建,且保證僅執(zhí)行一次創(chuàng)建。利用這個(gè)特點(diǎn),可以像如下實(shí)現(xiàn):

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading.Tasks; 6:? 7: namespace SingletonNotUsingLock 8: { 9: public class Singleton 10: { 11: private volatile static Singleton instance = new Singleton(); 12:? 13: // Explicit static constructor to tell C# compiler 14: // not to mark type as beforefieldinit 15: static Singleton() 16: { 17: Console.WriteLine("execute static constructor"); 18: } 19:? 20: private Singleton() 21: { 22: Console.WriteLine("execute private constructor"); 23: } 24:? 25: public static Singleton Instance 26: { 27: get 28: { 29: Console.WriteLine("instance get"); 30: return instance; 31: } 32: } 33: } 34: }

上面的代碼可以更簡(jiǎn)化一些,去掉Instance屬性,將私有的instance變量改成public的:

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading.Tasks; 6:? 7: namespace SingletonNotUsingLock 8: { 9: public class Singleton2 10: { 11: public volatile static Singleton2 instance = new Singleton2(); 12:? 13: // Explicit static constructor to tell C# compiler 14: // not to mark type as beforefieldinit 15: static Singleton2() 16: { 17: Console.WriteLine("execute static constructor"); 18: } 19:? 20: private Singleton2() 21: { 22: Console.WriteLine("execute private constructor"); 23: } 24: } 25: }

代碼非常簡(jiǎn)潔。但是為什么有個(gè)靜態(tài)構(gòu)造函數(shù)呢,我們看看下面的測(cè)試代碼:

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading.Tasks; 6:? 7: namespace SingletonNotUsingLock 8: { 9: class Program 10: { 11: static void Main(string[] args) 12: { 13: Console.WriteLine("begin create singleton"); 14:? 15: Singleton s1 = Singleton.Instance; 16:? 17: Console.WriteLine("after create singleton"); 18:? 19: Singleton2 s2 = Singleton2.instance; 20:? 21: Console.WriteLine("after create singleton2"); 22: } 23: } 24: }

執(zhí)行結(jié)果如下:

把靜態(tài)構(gòu)造函數(shù)去掉后執(zhí)行結(jié)果如下:

這是因?yàn)闆](méi)有靜態(tài)構(gòu)造函數(shù)的類(lèi),編譯時(shí)會(huì)被標(biāo)記稱(chēng)beforefieldinit,那么,beforefieldinit究竟表示什么樣的語(yǔ)義呢?Scott Allen對(duì)此進(jìn)行了詳細(xì)的解釋:beforefieldinit為CLR提供了在任何時(shí)候執(zhí)行.cctor的授權(quán),只要該方法在第一次訪(fǎng)問(wèn)類(lèi)型的靜態(tài)字段之前執(zhí)行即可。

實(shí)現(xiàn)5:無(wú)鎖懶加載

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading.Tasks; 6:? 7: namespace SingletonNotUsingLockAndLazyLoad 8: { 9: public class Singleton 10: { 11: private Singleton() 12: { 13: Console.WriteLine("execute Singleton private constructor"); 14: } 15:? 16: public static Singleton Instance 17: { 18: 19: get 20: { 21: Console.WriteLine("execute Singleton.Instance get"); 22: return Nested.instance; 23: } 24: } 25:? 26: private class Nested 27: { 28: // Explicit static constructor to tell C# compiler 29: // not to mark type as beforefieldinit 30: static Nested() 31: { 32: Console.WriteLine("execute Nested static constructor"); 33: } 34:? 35: internal static readonly Singleton instance = new Singleton(); 36: } 37: } 38: }

實(shí)現(xiàn)6:使用.NET 4.0中的Lazy<T>

1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading.Tasks; 6:? 7: namespace SingletonUsingLazyType 8: { 9: public sealed class Singleton 10: { 11: private static readonly Lazy<Singleton> lazy = 12: new Lazy<Singleton>(() => new Singleton()); 13:? 14: public static Singleton Instance { get { return lazy.Value; } } 15:? 16: private Singleton() 17: { 18: } 19: } 20: }

參考:

  • Exploring the Singleton Design Pattern
  • C#設(shè)計(jì)模式(7)-Singleton Pattern
  • Implementing the Singleton Pattern in C#
  • c#靜態(tài)構(gòu)造函數(shù)
  • C# and beforefieldinit
  • 《研磨設(shè)計(jì)模式》
  • 關(guān)于Type Initializer和 BeforeFieldInit的問(wèn)題,看看大家能否給出正確的解釋
  • [你必須知道的.NET]第二十三回:品味細(xì)節(jié),深入.NET的類(lèi)型構(gòu)造器
  • 轉(zhuǎn)載于:https://www.cnblogs.com/EthanCai/p/3150595.html

    總結(jié)

    以上是生活随笔為你收集整理的设计模式之一:单例模式(Singleton Pattern)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 69国产在线 | 天天干视频在线观看 | 日韩视频一区二区三区在线播放免费观看 | 人人夜| 日韩国产欧美视频 | 美女福利网站 | 国产日日夜夜 | 国产女人18水真多18精品一级做 | 蜜桃精品久久久久久久免费影院 | 久操这里只有精品 | 日日碰狠狠添天天爽无码 | 国产乱码精品1区2区3区 | 一级黄色片在线免费观看 | 操大逼网站 | 97超碰国产在线 | 麻豆精品视频在线 | 成人av片免费看 | 日韩免费一区二区 | 成人短视频在线免费观看 | 亚洲美女屁股眼交8 | 女女h百合无遮涩涩漫画软件 | 国产精品亚洲一区二区三区在线观看 | 国产日韩视频 | 国模吧一区二区 | 久免费一级suv好看的国产 | 女女互慰吃奶互揉调教捆绑 | 91亚洲精品久久久蜜桃借种 | 国产精品婷婷午夜在线观看 | 日韩国产传媒 | 性感少妇在线观看 | 青青草香蕉 | 欧美极品视频在线观看 | 亚洲成人黄色影院 | 亚洲成人av一区 | 欧美色图片区 | 伊人网综合视频 | 激情五月综合 | 日韩黄色录像 | 久久九九国产精品 | 天天插天天爽 | 国产第20页| caoporen超碰| 天天做天天干 | 被黑人各种姿势猛c哭h文1 | 日本wwwwwww| 娇妻av| 日本精品一区二区三区在线观看 | 午夜嘿嘿| 欧美11一13sex性hd | 人人干天天操 | 在线亚洲观看 | 丰满人妻一区二区三区53视频 | 少妇久久久| 蜜桃麻豆视频 | www.夜夜爽 | 成年人黄色在线观看 | 欧美日韩成人免费 | 日韩电影福利 | 老汉av| 精品婷婷色一区二区三区蜜桃 | 一区二区福利视频 | 99国产在线播放 | 久草网视频 | 青青草黄色 | 色婷婷在线视频 | 日韩人妻无码精品综合区 | 91夫妻论坛 | av色婷婷| 亚洲天堂一区 | 五月综合色婷婷 | 久久久久久婷婷 | 一级黄色免费片 | 色哟哟日韩精品 | 欧美伦理一区 | 在线看片福利 | www.av免费 | 一久久 | 五月天激情开心网 | 日本理论片午伦夜理片在线观看 | 一本色道综合久久欧美日韩精品 | xnxx国产| 少妇熟女视频一区二区三区 | 精品无码国产污污污免费网站 | 夜夜骑天天干 | 无码 制服 丝袜 国产 另类 | 亚洲av无码一区二区三区在线 | 另类男人与善交video | 久久精品中文闷骚内射 | 99视频观看| 色又色 | 亚洲精品2区 | 热久久伊人 | 青草青在线 | 视频免费观看在线 | 狠狠干狠狠干狠狠干 | 男人午夜免费视频 | 天天狠天天插天天透 | www.色欧美 | 欧美日韩一区二区三区四区 |