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

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

      生活随笔

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

      asp.net

      【设计模式】单例模式 Singleton Pattern

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

      通常我們?cè)趯懗绦虻臅r(shí)候會(huì)碰到一個(gè)類只允許在整個(gè)系統(tǒng)中只存在一個(gè)實(shí)例(Instance)? 的情況, 比如說(shuō)我們想做一計(jì)數(shù)器,統(tǒng)計(jì)某些接口調(diào)用的次數(shù),通常我們的數(shù)據(jù)庫(kù)連接也是只期望有一個(gè)實(shí)例。Windows系統(tǒng)的系統(tǒng)任務(wù)管理器也是始終只有一個(gè),如果你打開(kāi)了windows管理器,你再想打開(kāi)一個(gè)那么他還是同一個(gè)界面(同一個(gè)實(shí)例), 還有比如 做.Net平臺(tái)的人都知道,AppDomain 對(duì)象,一個(gè)系統(tǒng)中也只有一個(gè),所有的類庫(kù)都會(huì)加載到AppDomain中去運(yùn)行。只需要一個(gè)實(shí)例對(duì)象的場(chǎng)景,隨處可見(jiàn),那么有么有什么好的解決方法來(lái)應(yīng)對(duì)呢? 有的,那就是 單例模式。

      一、單例模式定義

      單例模式(Singleton Pattern):確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例,這個(gè)類稱為單例類,它提供全局訪問(wèn)的方法。單例模式是一種對(duì)象創(chuàng)建型模式。

      二、單例模式結(jié)構(gòu)圖

      • Singleton(單例):在單例類的內(nèi)部實(shí)現(xiàn)只生成一個(gè)實(shí)例,同時(shí)它提供一個(gè)靜態(tài)的GetInstance()工廠方法,讓客戶可以訪問(wèn)它的唯一實(shí)例;為了防止在外部對(duì)其實(shí)例化,將其構(gòu)造函數(shù)設(shè)計(jì)為私有(private);在單例類內(nèi)部定義了一個(gè)Singleton類型的靜態(tài)對(duì)象,作為外部共享的唯一實(shí)例。

      三、 單例模式典型代碼

      public class Singleton {private static Singleton instance;private Singleton(){}public static Singleton GetInstance(){if(instance==null){instance=new Singleton();}return instance;} }

      客戶端調(diào)用代碼:

      static void Main(string[] args) {Singleton singleto = Singleton.GetInstance(); }

      在C#中經(jīng)常將統(tǒng)一訪問(wèn)點(diǎn)暴露出一個(gè)只讀的屬性供客戶端程序使用,這樣代碼就變成了這樣:

      public class Singleton {private static Singleton instance;private Singleton(){}public static Singleton GetInstance{get{if (instance == null){instance = new Singleton();}return instance;}} }

      客戶端調(diào)用:

      static void Main(string[] args) {Singleton singleton = Singleton.GetInstance; }

      四、單例模式實(shí)例

      1. 懶漢模式

      假如我們要做一個(gè)程序計(jì)數(shù)器,一旦程序啟動(dòng)無(wú)論多少個(gè)客戶端調(diào)用這個(gè) 計(jì)數(shù)器計(jì)數(shù)的結(jié)果始終都是在前一個(gè)的基礎(chǔ)上加1,那么這個(gè)計(jì)數(shù)器類就可以設(shè)計(jì)成一個(gè)單例模式的類。

      public class SingletonCounter {private static SingletonCounter instance;private static int number=0;private SingletonCounter() { }public static SingletonCounter Instance{get{if (instance == null) instance = new SingletonCounter();number++;return instance;}}public int GetCounter(){return number;} }

      客戶端調(diào)用:

      static void Main(string[] args) {//App A call the counter;SingletonCounter singletonA = SingletonCounter.Instance;int numberA = singletonA.GetCounter();Console.WriteLine("App A call the counter get number was:" + numberA);//App B call the counter;SingletonCounter singletonB = SingletonCounter.Instance;int numberB = singletonA.GetCounter();Console.WriteLine("App B call the counter get number was:" + numberB);Console.ReadKey(); }

      輸出結(jié)果:

      這個(gè)實(shí)現(xiàn)是線程不安全的,如果有多個(gè)線程同時(shí)調(diào)用,并且又恰恰在計(jì)數(shù)器初始化的瞬間多個(gè)線程同時(shí)檢測(cè)到了 instance==null為true情況,會(huì)怎樣呢?這就是下面要討論的 “加鎖懶漢模式”

      2、加鎖懶漢模式

      多個(gè)線程同時(shí)調(diào)用并且同時(shí)檢測(cè)到 instance == null 為 true的情況,那后果就是會(huì)出現(xiàn)多個(gè)實(shí)例了,那么就無(wú)法保證唯一實(shí)例了,解決這個(gè)問(wèn)題就是增加一個(gè)對(duì)象鎖來(lái)確保在創(chuàng)建的過(guò)程中只有一個(gè)實(shí)例。(鎖可以確保鎖住的代碼塊是線程獨(dú)占訪問(wèn)的,如果一個(gè)線程占有了這個(gè)鎖,其它線程只能等待該線程釋放鎖以后才能繼續(xù)訪問(wèn))。

      public class SingletonCounter {private static SingletonCounter instance;private static readonly object locker = new object();private static int number = 0;private SingletonCounter() { }public static SingletonCounter Instance{get{lock (locker){if (instance == null) instance = new SingletonCounter();number++;return instance;}}}public int GetCounter(){return number;} }

      客戶端調(diào)用代碼:

      static void Main(string[] args) { for (int i = 1; i < 100; i++){var task = new Task(() =>{SingletonCounter singleton = SingletonCounter.Instance;int number = singleton.GetCounter();Console.WriteLine("App call the counter get number was:" + number);});task.Start();}Console.ReadKey(); }

      輸出結(jié)果:

      這種模式是線程安全,即使在多線程的情況下仍然可以保持單個(gè)實(shí)例。那么這種模式會(huì)不會(huì)有什么問(wèn)題呢?假如系統(tǒng)的訪問(wèn)量非常大,并發(fā)非常高,那么計(jì)數(shù)器就會(huì)是一個(gè)性能瓶頸,因?yàn)閷?duì)鎖會(huì)使其它的線程無(wú)法訪問(wèn)。在訪問(wèn)量不大,并發(fā)量不高的系統(tǒng)尚可應(yīng)付,如果高訪問(wèn)量,高并發(fā)的情況下這樣做肯定是不行的,那么有什么辦法改進(jìn)呢?這就是下面要討論的“雙檢查加鎖懶漢模式”。

      3、雙檢查加鎖懶漢模式

      加鎖懶漢模式雖然保證了系統(tǒng)的線程安全,但是卻為系統(tǒng)帶來(lái)了新能問(wèn)題,主要的性能來(lái)自鎖帶來(lái)開(kāi)銷,雙檢查就是解決這個(gè)鎖帶來(lái)的問(wèn)題,在鎖之前再做一次 instance==null的檢查,如果返回true就直接返回 單例對(duì)象了,避開(kāi)了無(wú)謂的鎖, 我們來(lái)看下,雙檢查懶漢模式代碼:

      public class DoubleCheckLockSingletonCounter {private static DoubleCheckLockSingletonCounter instance;private static readonly object locker = new object();private static int number = 0;private DoubleCheckLockSingletonCounter() { }public static DoubleCheckLockSingletonCounter Instance{get{if (instance == null){lock (locker){if (instance == null){instance = new DoubleCheckLockSingletonCounter();}}}number++;return instance;}}public int GetCounter(){return number;} }

      客戶端調(diào)用代碼和“懶漢加鎖模式”相同,輸出結(jié)果也相同。

      4、餓漢模式

      單例模式除了我們上面講的三種懶漢模式外,還有一種叫“餓漢模式”的實(shí)現(xiàn)方式,“餓漢模式”直接在Singleton類里實(shí)例化了當(dāng)前類的實(shí)例,并且保存在一個(gè)靜態(tài)對(duì)象中,因?yàn)槭庆o態(tài)對(duì)象,所以在程序啟動(dòng)的時(shí)候就已經(jīng)實(shí)例化好了,后面直接使用,因此不存在線程安全的問(wèn)題。

      下面是“餓漢模式”的代碼實(shí)現(xiàn):

      public class EagerSingletonCounter {private static EagerSingletonCounter instance = new EagerSingletonCounter();private static int number = 0;private EagerSingletonCounter() { }public static EagerSingletonCounter Instance{get{number++;return instance;}}public int GetCounter(){return number;} }

      ?

      五、單例模式應(yīng)用場(chǎng)景

      單例模式只有一個(gè)角色非常簡(jiǎn)單,使用的場(chǎng)景也很明確,就是一個(gè)類只需要、且只能需要一個(gè)實(shí)例的時(shí)候使用單例模式。

      六、擴(kuò)展

      ?

      1、”餓漢模式“和”懶漢模式“的比較

      ”餓漢模式“在程序啟動(dòng)的時(shí)候就已經(jīng)實(shí)例化好了,并且一直駐留在系統(tǒng)中,客戶程序調(diào)用非常快,因?yàn)樗庆o態(tài)變量,雖然完美的保證線程的安全,但是如果創(chuàng)建對(duì)象的過(guò)程很復(fù)雜,要占領(lǐng)系統(tǒng)或者網(wǎng)絡(luò)的一些昂貴的資源,但是在系統(tǒng)中使用的頻率又極低,甚至系統(tǒng)運(yùn)行起來(lái)后都不會(huì)去使用該功能,那么這樣一來(lái),啟動(dòng)之后就一直占領(lǐng)著系統(tǒng)的資源不釋放,這有些得不償失。

      “懶漢模式“ 恰好解決了”餓漢模式“這種占用資源的問(wèn)題,”懶漢模式”將類的實(shí)例化延遲到了運(yùn)行時(shí),在使用時(shí)的第一次調(diào)用時(shí)才創(chuàng)建出來(lái)并一直駐留在系統(tǒng)中,但是為了解決線程安全問(wèn)題, 使用對(duì)象鎖也是 影響了系統(tǒng)的性能。這兩種模式各有各的好處,但是又各有其缺點(diǎn)。

      有沒(méi)有一種折中的方法既可以避免一開(kāi)始就實(shí)例化且一直占領(lǐng)系統(tǒng)資源,又沒(méi)有性能問(wèn)題的Singleton呢? 答案是:有的。

      2、第三種選擇

      “餓漢模式“類不能實(shí)現(xiàn)延遲加載,不管用不用始終占據(jù)內(nèi)存;”懶漢式模式“類線程安全控制煩瑣,而且性能受影響。我們用一種折中的方法來(lái)解決這個(gè)問(wèn)題,針對(duì)主要矛盾, 即:既可以延時(shí)加載又不影響性能。

      在Singleton的內(nèi)部創(chuàng)建一個(gè)私有的靜態(tài)類用于充當(dāng)單例類的”初始化器“,專門用來(lái)創(chuàng)建Singleton的實(shí)例:

      public class BestPracticeSingletonCounter {private static class SingletonInitializer{public static BestPracticeSingletonCounter instance = new BestPracticeSingletonCounter();} private static int number = 0;private BestPracticeSingletonCounter() { }public static BestPracticeSingletonCounter Instance{get{number++;return SingletonInitializer.instance;}}public int GetCounter(){return number;} }

      這種模式兼具了”餓漢“和”懶漢“模式的優(yōu)點(diǎn)有摒棄了其缺點(diǎn),可以說(shuō)是一個(gè)完美的實(shí)現(xiàn)。

      總結(jié)

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

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