丨單例模式如何創(chuàng)建單一對(duì)象優(yōu)化系統(tǒng)性能_第1頁(yè)
丨單例模式如何創(chuàng)建單一對(duì)象優(yōu)化系統(tǒng)性能_第2頁(yè)
丨單例模式如何創(chuàng)建單一對(duì)象優(yōu)化系統(tǒng)性能_第3頁(yè)
丨單例模式如何創(chuàng)建單一對(duì)象優(yōu)化系統(tǒng)性能_第4頁(yè)
丨單例模式如何創(chuàng)建單一對(duì)象優(yōu)化系統(tǒng)性能_第5頁(yè)
已閱讀5頁(yè),還剩16頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

結(jié)合這三點(diǎn),我們來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單代碼//餓漢模publicfinalclassSingletonprivatestaticSingletoninstance=newSingleton();//自行創(chuàng)建實(shí)privateSingleton(){}//構(gòu)造函publicstaticSingletongetInstance(){//通過(guò)該函數(shù)向整個(gè)系統(tǒng)提供return 8我們可以發(fā)現(xiàn),以上第一種實(shí)現(xiàn)單例的代碼中,使用了static了成員instance,所以該變量會(huì)在類(lèi)初始化的過(guò)程中被收集進(jìn)類(lèi)構(gòu)造器即<clinit>方法中。在多線程場(chǎng)景下,JVM會(huì)保證只有一個(gè)線程能執(zhí)行該類(lèi)的<clinit>方法,其它線程將會(huì)被阻塞等待。等到唯一的一次<clinit>方法執(zhí)行完成,其它線程將不會(huì)再執(zhí)行<clinit>方法,轉(zhuǎn)而執(zhí)行自己的代碼。也就是說(shuō),static修飾了成員變量instance,在多線程的情況下能保證只實(shí)餓漢模式實(shí)現(xiàn)的單例的優(yōu)點(diǎn)是,可以保證多線程情況下實(shí)例的唯一性,而且直接返回唯一實(shí)例,性能非情況下,一直占用堆內(nèi)存。試想下,如果一個(gè)第開(kāi)源框架中的類(lèi)都是基于餓漢模式實(shí)的單例,這將會(huì)初始化所有單例類(lèi),無(wú)疑是性的懶漢模式就是為了避免直接加載類(lèi)對(duì)象時(shí)提前創(chuàng)建對(duì)象的一種單例設(shè)計(jì)模式。該模式使用懶加載方式,只有當(dāng)系統(tǒng)使用到類(lèi)對(duì)象時(shí),才會(huì)將實(shí)例加載到堆內(nèi)存中。通過(guò)以下代碼,我們可以簡(jiǎn)單地了解下懶加載的實(shí)現(xiàn)方式:代碼//懶漢模publicfinalclassSingletonprivatestaticSingletoninstance=null;//不實(shí)例privateSingleton(){}//構(gòu)造函publicstaticSingletongetInstance(){//通過(guò)該函數(shù)向整個(gè)系統(tǒng)提供if(null==instance){//當(dāng)instance為null時(shí),則實(shí)例化對(duì)象,否則直接返回instance=newSingleton();//實(shí)例化對(duì) returninstance;//返回已存在的 11當(dāng)線程A入到if斷條件后,開(kāi)始實(shí)例化對(duì)象,此時(shí)instance然為null;又有線程B進(jìn)入到if判斷條件中,之后也會(huì)通過(guò)條件判斷,進(jìn)入到方法里面創(chuàng)建一個(gè)實(shí)例對(duì)象。所以我們需要對(duì)該方法進(jìn)行加鎖,保證多線程情況下僅創(chuàng)建一個(gè)實(shí)例。這里我們使Synchronized鎖來(lái)修飾getInstance法代碼//懶漢模式+synchronized同步publicfinalclassSingletonprivatestaticSingletoninstance=null;//不實(shí)例privateSingleton(){}//構(gòu)造函publicstaticsynchronizedSingletongetInstance(){//加同步鎖,通過(guò)該函數(shù)向整個(gè)系if(null==instance){//當(dāng)instance為null時(shí),則實(shí)例化對(duì)象,否則直接返回instance=newSingleton();//實(shí)例化對(duì) returninstance;//返回已存在的 11還有,每次請(qǐng)求獲取類(lèi)對(duì)象時(shí),都會(huì)通過(guò)getInstance()方法獲取,除了第一次為l它每次請(qǐng)求基本都是不為l的。在沒(méi)有加同步鎖之前,是因?yàn)閒判斷條件為l導(dǎo)致創(chuàng)建了多個(gè)實(shí)例。基于以上兩點(diǎn),我們可以考慮將同步鎖放在f條件里面,這樣就可以減少同步鎖資源競(jìng)爭(zhēng)。代碼//懶漢模式+synchronized同步publicfinalclassSingletonprivatestaticSingletoninstance=null;//不實(shí)例privateSingleton(){}//構(gòu)造函publicstaticSingletongetInstance(){//加同步鎖,通過(guò)該函數(shù)向整個(gè)系統(tǒng)提供if(null==instance){//當(dāng)instance為null時(shí),則實(shí)例化對(duì)象,否則直接返回synchronizedinstance=newSingleton();//實(shí)例化對(duì) }returninstance;//返回已存在的 13if判斷條件里,雖然有同步鎖,但是進(jìn)入到判斷條件里面的線程依然會(huì)依次獲取到鎖創(chuàng)建對(duì)象,然后再釋放同步鎖。所以我們還需要在同步鎖里面再加一個(gè)判斷條件:代碼//懶漢模式+synchronized同步鎖+double-publicfinalclassSingletonprivatestaticSingletoninstance=null;//不實(shí)例privateSingleton(){}//構(gòu)造函publicstaticSingletongetInstance(){//加同步鎖,通過(guò)該函數(shù)向整個(gè)系統(tǒng)提供if(null==instance){//第一次判斷,當(dāng)instance為null時(shí),則實(shí)例化對(duì)象,否則直synchronized(Singleton.class){//同步if(null==instance){//第二次判9

instance=newSingleton();//實(shí)例化對(duì)}returninstance;//返回已存在的}}以上這種方式,通常被稱(chēng)為Double-Check,它可以大大提高支持多線程的懶漢模式的運(yùn)其實(shí)這里又跟Happens-Before規(guī)則和重排序扯上關(guān)系了,這里我們先來(lái)簡(jiǎn)單了解Happens-Before規(guī)則和重排序我們?cè)诘诙诓椭羞^(guò)譯器盡可減少器的、數(shù),分復(fù)用寄存器的值,比如以下代碼,如果沒(méi)有進(jìn)行重排序優(yōu)化,正常的執(zhí)行順序是步驟\\,而在編譯期間進(jìn)行了重排序優(yōu)化之后,執(zhí)行的步驟有可能就變成了步驟/2樣就能減少一次寄存器的存取次數(shù)。代碼inta=1;//步驟1:加載a變量的內(nèi)存地址到寄存器中,加載1到寄存器中,CPU通過(guò)mov指令intb=2;//步驟2加載b變量的內(nèi)存地址到寄存器中,加載2到寄存器中,CPU通過(guò)mov指令把a(bǔ)=a+1;//步驟3重新加載a變量的內(nèi)存地址到寄存器中,加載1到寄存器中,CPU通過(guò)mov在JMM中,重排序是十分重要的一環(huán),特別是在并發(fā)編程中。如果JVM任意排序以提高程序性能,也可能會(huì)給并發(fā)編程帶來(lái)一系列的問(wèn)題。例如,我上面講到的oub-Check的單例問(wèn)題,假設(shè)類(lèi)中有其它的屬性也需要實(shí)例化,這個(gè)時(shí)候,除了要實(shí)例化單例類(lèi)本身,還需要對(duì)其它屬性也進(jìn)行實(shí)例化:代碼//懶漢模式+synchronized同步鎖+double-publicfinalclassSingletonprivatestaticSingletoninstance=null;//不實(shí)例publicList<String>list=null;//list屬privatelist=new}//構(gòu)造函8918

publicstaticSingletongetInstance(){//加同步鎖,通過(guò)該函數(shù)向整個(gè)系統(tǒng)提供if(null==instance){//第一次判斷,當(dāng)instance為null時(shí),則實(shí)例化對(duì)象,否則直synchronized(Singleton.class){//同步if(null==instance){//第二次判instance=newSingleton();//實(shí)例化對(duì)}}}returninstance;//返回已存在的}在執(zhí)行instance=newSingleton();代碼時(shí),正常情況下,實(shí)例過(guò)程這樣給Singleton分配內(nèi)存調(diào)用Singleton的構(gòu)造函數(shù)來(lái)初始化成員變將Singleton對(duì)象指向分配的內(nèi)存空間(執(zhí)行完這步singleton就為非null了)如果虛擬機(jī)發(fā)生了重排序優(yōu)化,這個(gè)時(shí)候步驟3可能發(fā)生在步驟2之前。如果初始化線程剛好完成步驟3,而步驟2沒(méi)有進(jìn)行時(shí),則剛好有另一個(gè)線程到了第一次判斷,這個(gè)時(shí)候判斷為非null,并返回對(duì)象使用,這個(gè)時(shí)候?qū)嶋H沒(méi)有完成其它屬性的構(gòu)造,因此使用這個(gè)屬性就很可能會(huì)導(dǎo)致異常。在這里,Synchronized只能保證可見(jiàn)性、原子性,無(wú)法保證執(zhí)這個(gè)時(shí)候,就體現(xiàn)出Happens-Before規(guī)則的重要性了。通過(guò)字面意思,你可能會(huì)誤以為我們知道volatile關(guān)鍵字可以保證線程間變量的可見(jiàn)性,簡(jiǎn)單地說(shuō)就是當(dāng)線程A對(duì)變量X進(jìn)行修改后,程A后面執(zhí)行的其它線程就能看到變量X的變動(dòng)。除此之外,volatile在JDK1.5之后還有一個(gè)作用就是局部重排序的發(fā)生,也就是說(shuō),volatile變量的操作指令都不會(huì)被重排序。所以使用volatile修飾instance之后,Double-Check懶漢單例模代碼//懶漢模式+synchronized同步鎖+double-publicfinalclassSingletonprivatevolatilestaticSingletoninstance=null;//不實(shí)例publicList<String>list=null;//list屬private6list=new7}//構(gòu)造函8publicstaticSingletongetInstance(){//加同步鎖,通過(guò)該函數(shù)向整個(gè)系統(tǒng)提供9if(null==instance){//第一次判斷,當(dāng)instance為null時(shí),則實(shí)例化對(duì)象,否則直synchronized(Singleton.class){//同步if(null==instance){//第二次判instance=newSingleton();//實(shí)例化對(duì)}}}returninstance;//返回已存在的}}以上這種同步鎖+Double-Check實(shí)現(xiàn)方式相對(duì)來(lái)說(shuō),復(fù)雜且加了同步鎖,那有沒(méi)有稍我們知道,在餓漢模式中,我們使用了static修飾了成員變量instance,所以該變量會(huì)在類(lèi)初始化的過(guò)程中被收集進(jìn)類(lèi)構(gòu)造器即<clinit>方法中。在多線程場(chǎng)景下,JVM會(huì)保證只有一個(gè)線程能執(zhí)行該類(lèi)的<clinit>方法,其它線程將會(huì)被阻塞等待。這種方式可以保證內(nèi)如果我們?cè)赟ingleton類(lèi)中創(chuàng)建一個(gè)內(nèi)部類(lèi)來(lái)實(shí)現(xiàn)成員變量的初始化,則可以避免多線程下重復(fù)創(chuàng)建對(duì)象的情況發(fā)生。這種方式,只有在第一次調(diào)用getInstance()方法時(shí),才會(huì)加載InnerSingleton類(lèi),而只有在加載InnerSingleton類(lèi)之后,才會(huì)實(shí)例化創(chuàng)建對(duì)象。具代碼//懶漢模式內(nèi)部類(lèi)實(shí)publicfinalclassSingletonpublicList<String>list=null;//list屬4privateSingleton(){//構(gòu)造函list=new 8 //內(nèi)部類(lèi)17

publicstaticclassInnerSingletonprivatestaticSingletoninstance=newSingleton();//自行創(chuàng)建實(shí)}publicstaticSingletongetInstance()returnInnerSingleton.instance;//返回內(nèi)部類(lèi)中的靜態(tài)變}如果我們?cè)诔绦騿?dòng)后,一定會(huì)加載到類(lèi),那么用餓漢模式實(shí)現(xiàn)的單例簡(jiǎn)單又實(shí)用;如果我們是寫(xiě)一些工具類(lèi),則優(yōu)先考慮使用懶漢模式,因?yàn)楹芏囗?xiàng)目可能會(huì)到r,但未除了以上那些實(shí)現(xiàn)單例的方式,你還知道其它實(shí)現(xiàn)方 科技所有 不 售賣(mài)。頁(yè)面已增加防盜追蹤,將依 上一 25|答疑課堂:模塊四熱點(diǎn)問(wèn)題解下一 27|原型模式與享元模式:提升系統(tǒng)性能的利精選留言展9使用枚舉來(lái)實(shí)現(xiàn)單例模式,具體代碼如下:publicclass{privatestaticSinletonExample5instance=private展7相比DoubleCheck,以?xún)?nèi)部類(lèi)方式實(shí)現(xiàn)單例模式,代碼簡(jiǎn)潔,性能相近,在我看來(lái)是更優(yōu)展3展3方式和枚

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論