小看--单例设计模式
? ? (一)單例設計描述
? ? ? 只要了解過設計模式的同學都會知道:單例設計模式,大家都知道單例設計模式是一種創建行的設計模式。既然是創建型,那么先來講講,對象的創建的過程吧。
? ? ?--靜態成員:靜態成員在程序加載的時候,就會加載進內存。
? ? ?--實例成員:只有new的時候才有實例成員。1、為實例的數據字段分配內存,然后初始化對象的附加字段(類型指針和同步索引塊),最后調用類型的實例構造器來設置對象的初始化狀態。
? ? ? 單例模式:一般用在一個類的創建對象很消耗資源,消耗時間,并且系統要保證只有一個對象的時候。一句話,對象的創建并不是很耗時間,不要刻意去套用單例模式,單例模式必須是在單例的時候,才單例。
? ? (二)?單例模式的演變
? ? ? ? 下面我們來模擬實際情況
public class Singleton {/// <summary>/// 對象會持有資源/// </summary>private List<string> _connList=new List<string>(){"測試數據庫連接","測試數據庫連接2","測試數據庫連接3","測試數據庫連接4"};public Singleton(){long lResult = 0;for (int i = 0; i < 100000; i++){lResult += i;}Thread.Sleep(1000);Console.WriteLine("{0}被構造一次",this.GetType().Name);}public void Show(){Console.WriteLine("調用了Show");}}? ? ? 這個類的創建需要耗費很多資源,里面有個Show方法。
? ? ? 那么接下來,實際中,我們可能有十個地方要用到這個類里面的Show方法,我們的做法是這樣的
//那么接下來,我們這里要調用十次Show方法for (var i = 0; i < 10; i++) {var singletonObj = new Singleton();singletonObj.Show();}? ????
?
? ? 這里每次調用一次,都需要耗費很多資源和時間,這里可能有些同學就會說,那我把這個singletonObj=new Singleton()提取出來,放到最外面來。
? ? 那行,按照我們需要,我們把var singletonObj=new Singletone()放到外面,如下所示
? ?
? 貌似這樣就解決了我們的問題,但是各位你們想一想,我們一個系統是有多個人開發的,A這里這樣做,B可能不知道這里有這個聲明,那他可能就還是一樣去New Singleton,還是導致我們系統中,存在大量這個對象。
? 我們應該要如何解決這個問題呢??如何保證這個對象在整個系統只被創建一次呢?
? 單例模式--單線程
? 從上面的問題,我們也可以看出因為誰都可以在New Singleton,所以導致了這個問題。那按照這個想法,那我們就想啦,那就把構造函數私有化唄,私有化完了之后,我們應該還要提供一個方法或者啥的,給外面調用(也只能是靜態的成員),構造函數私有化了,外面是不可以New了的
? ?那就按照,剛剛的說法,我們來進行一次改進
public class Singleton {/// <summary>/// 對象會持有資源/// </summary>private List<string> _connList=new List<string>(){"測試數據庫連接","測試數據庫連接2","測試數據庫連接3","測試數據庫連接4"};private Singleton(){long lResult = 0;for (int i = 0; i < 100000; i++){lResult += i;}Thread.Sleep(1000);Console.WriteLine("{0}被構造一次",this.GetType().Name);}public static Singleton CreateInstance(){return new Singleton();}public void Show(){Console.WriteLine("調用了Show");}}? ? 按照我們上面這個寫法,把構造函數私有化了,然后在靜態方法里面New Singletone();
? ? 調用結果如下:
for (var i = 0; i < 10; i++) {var singletonObj = Singleton.CreateInstance();singletonObj.Show();} //寫進里面去了,是為了模擬有十個不同的開發,再調用?
? 那結果,還是沒有達到我們想要的,那現在問題就是,對象沒有重用,因為我們每次new,導致了對象沒有做到重用,那就讓對象進行重用唄。最簡單的方法,就是給一個靜態的字段(為啥靜態呢,因為我們那邊方法是靜態的),然后做一個判斷,如果對象為空,那么我們就創建,如果不為空,就不用創建了,如下所示。? ??
? ?
? ?我們在原來的基礎上,做了如上圖的改進。結果如下,
? ?
? ?我們想要的結果實現了,多次調用的時候,做了重用對象,只構造了一次。本來想著單例模式就這樣結束了(單線程是沒有問題,并且這種實現是一種懶漢式,懶漢式:當你需要用這個類的時候,才會去實例化)。
? ?編程世界里面,我們總是要考慮一下,多線程的情況。
? ?單例模式--多線程
? ?這個是用Task.Run()開啟了也給多線程的異步調用
for (var i = 0; i < 10; i++){Task.Run(()=>{var singletonObj = Singleton.CreateInstance();singletonObj.Show();}); }Thread.Sleep(5000);? ?
? ?通過上面的結果,我們可以看出,我們的之前的做法,在多線程環境還是會調用多次。
? ?有些同學就會說用lock鎖啦,行,我們就給他加上一把鎖。
public class Singleton {/// <summary>/// 對象會持有資源/// </summary>private List<string> _connList=new List<string>(){"測試數據庫連接","測試數據庫連接2","測試數據庫連接3","測試數據庫連接4"};private static Singleton singletonObj = null;private static readonly object singleTonObjLock = new object(); //加鎖,之后這里為啥要用readonly,大家可以找private Singleton(){long lResult = 0;for (int i = 0; i < 100000; i++){lResult += i;}Thread.Sleep(1000);Console.WriteLine("{0}被構造一次",this.GetType().Name);Console.WriteLine($"線程{Thread.CurrentThread.ManagedThreadId}調用一次");}public static Singleton CreateInstance(){lock (singleTonObjLock) //很多同學都說用lock this,this肯定是不行的,因為lock是lock引用的,如果這個this的引用改變了... {if (singletonObj == null){singletonObj = new Singleton();}}return singletonObj;}public void Show(){Console.WriteLine("調用了Show");}}? ?看我們給他加完鎖的時候效果。
? ?
? ?嗯,實現了我們想要的效果了,說明我們加鎖是有效果的。到了這個時候,大家可能覺得一個單例模式應該就快結束了,那么我們再來看看這種情況。
? 單例模式--多線程(雙if+lock)
??
?
?通過上面的介紹,我們理解了單例模式的演變過程,也對單例模式,多線程有了更加深刻的印象。
?(三)單例模式其他實現
? ? 就像我們一開始說的那樣,單例模式,其實一個進程內,在多線程環境下,如何保證只有一個對象,這就是單例。也可以從這個定義看出,我們可以通過靜態的構造函數來實現一個單例模式。
? ? 靜態構造函數,是由CLR保證的,有且只會加載一次。
? ? 其他很多方法實現,都是利用static關鍵字的背后原因,在第一次使用類型之前被調用,且只會被調用一次。
? ?(四)懶漢式,餓漢式
? ? ? 懶漢,就是說這個人很懶,需要用的時候,才構建。雙if+lock這種就屬于懶漢式。懶漢式,利用了延遲加載加載的思想。
? ? ? 餓漢:就是調用我這個類型,就會幫你創建好;管你用不用,我都會幫你創建;就是餓了嗎,我后面介紹的利用static關鍵字的就是屬于餓漢式;餓漢式:管你之前有沒有(內存中),都會幫你new一個新的實例。
? ?(五)單例模式的使用場景
? ? ? ?單例:必須單例才單例,反正沒必要。單例模式實現都有性能,損失,靜態方法。
? ? ? ?單例:會把對象常駐內存,靜態的。
? ? ? ?單例的使用,多個人操作可能會對你影響,因為都是對同一份引用進行修改。
? ? ? ?一般用在數據庫連接,打印機,遠程服務調用,等等這些大對象身上。
? //單例模式的應用場景補充:讀取配置文件信息,讀取配置文件不應該一直new一個類,應該是單例的。
? ? ? ?
?
? ? ??
?
public class ConfigV1{private static object _lockObj = new object();private static ConfigV1 _instance;private static Dictionary<string,string> _configItems =new Dictionary<string, string>();private ConfigV1(){Init();Console.WriteLine($"{this.GetType().Name}被構造一次");}public static ConfigV1 GetInstance(){if (_instance == null){lock (_lockObj){if (_instance == null){_instance=new ConfigV1();}}}return _instance;}public string this[string item]{get{return _configItems[item];}}private void Init(){var config=ConfigurationManager.AppSettings.AllKeys;foreach(var key in config){_configItems.Add(key,ConfigurationManager.AppSettings[key]);}}}? ? ? ?github:https://github.com/gdoujkzz/DesignPattern.git
謝謝你閱讀我的博客,如果有收獲,請點一個贊(推薦)
? ? ?
?
? ?
?
?
?
? ? ?
轉載于:https://www.cnblogs.com/gdouzz/p/8319485.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的小看--单例设计模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 链家app怎么看成交记录(链家这些房产A
- 下一篇: ASP.NET Core 2.0 MVC