單例模式的好處:
單例模式的好處就是單例,就是全局唯一的一個(gè)實(shí)例,應(yīng)對(duì)一些特殊情況,比如數(shù)據(jù)庫連接池(內(nèi)置了資源)全局唯一奧瑪生成器,單例可以避免重復(fù)創(chuàng)建,但是也會(huì)常駐內(nèi)存,除非真的有必要,否則不要用單例模式。
單例模式:
1、構(gòu)造函數(shù)私有化,避免別人還去new
2、公開的靜態(tài)方法提供對(duì)象實(shí)例
3、初始化一個(gè)靜態(tài)字段用于返回,保證全局都是這一個(gè)。
/// <summary>/// 單例類:一個(gè)構(gòu)造對(duì)象很耗時(shí)耗資源類型/// 懶漢式單例模式/// </summary>public class Singleton{ /// <summary> /// 構(gòu)造函數(shù)耗時(shí)耗資源 /// </summary> private Singleton() { } /// <summary> /// 3 全局唯一靜態(tài) 重用這個(gè)變量 /// </summary> private static volatile Singleton _Singleton = null; /// <summary> /// 2 公開的靜態(tài)方法提供對(duì)象實(shí)例 /// </summary> /// <returns></returns> public static Singleton CreateInstance() { _Singleton = new Singleton(); return _Singleton; }}
可以用以object.ReferenceEquals來驗(yàn)證創(chuàng)建的實(shí)例是不是同一個(gè)
Singleton singleton1 = Singleton.CreateInstance(); Singleton singleton2 = Singleton.CreateInstance(); Singleton singleton3 = Singleton.CreateInstance(); Console.WriteLine(object.ReferenceEquals(singleton1, singleton2)); Console.WriteLine(object.ReferenceEquals(singleton3, singleton2));
在多線程下,同事開啟5個(gè)線程去創(chuàng)建呢?
for (int i = 0; i < 5; i++) { Task.Run(() =>//啟動(dòng)線程完成--5個(gè)線程并發(fā)執(zhí)行,同時(shí)去執(zhí)行這個(gè)方法 { Singleton singleton1 = Singleton.CreateInstance(); singleton1.Show(); }); }
這里就會(huì)出現(xiàn)多線程的問題,下面來解決多線程面臨的問題。
/// <summary>/// 單例類:一個(gè)構(gòu)造對(duì)象很耗時(shí)耗資源類型/// 懶漢式單例模式/// </summary>public class Singleton{ /// <summary> /// 構(gòu)造函數(shù)耗時(shí)耗資源 /// </summary> private Singleton() { long lResult = 0; for (int i = 0; i < 10000000; i++) { lResult += i; } Thread.Sleep(2000); Console.WriteLine("{0}被構(gòu)造一次", this.GetType().Name); } /// <summary> /// 3 全局唯一靜態(tài) 重用這個(gè)變量 /// </summary> private static volatile Singleton _Singleton = null; //volatile 促進(jìn)線程安全 讓線程按順序操作 private static readonly object Singleton_Lock = new object(); /// <summary> /// 2 公開的靜態(tài)方法提供對(duì)象實(shí)例 /// </summary> /// <returns></returns> public static Singleton CreateInstance() { if (_Singleton == null)//是_Singleton已經(jīng)被初始化之后,就不要進(jìn)入鎖等待了 { lock (Singleton_Lock) //保證任意時(shí)刻只有一個(gè)線程進(jìn)入lock范圍 //也限制了并發(fā),尤其是_Singleton已經(jīng)被初始化之后 { //Thread.Sleep(1000); //Console.WriteLine("等待鎖1s之后才繼續(xù)。。。"); if (_Singleton == null)//保證只實(shí)例化一次 { _Singleton = new Singleton(); } } } return _Singleton; } //既然是單例,大家用的是同一個(gè)對(duì)象,用的是同一個(gè)方法,那還會(huì)并發(fā)嗎 還有線程安全問題嗎? public int iTotal = 0; public void Show() { //lock (Singleton_Lock) //{ this.iTotal++; //} } public static void Test() { Console.WriteLine("Test1"); Console.WriteLine(_Singleton.iTotal); }}
聯(lián)系客服