




下載本文檔
版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、如何止確地寫(xiě)出單例模式編程 開(kāi)發(fā)技術(shù)如何正確地寫(xiě)出單例模式原文出處:伍艸單例模式算是設(shè)計(jì)模式中最容易理解,也是最容易手寫(xiě)代碼的模式了吧。但是其 中的坑卻不少,所以也常作為面試題來(lái)考。本文主耍對(duì)幾種單例寫(xiě)法的整理,并 分析其優(yōu)缺點(diǎn)。很多都是一些老生常談的問(wèn)題,但如果你不知道如何創(chuàng)建一個(gè)線(xiàn) 程安全的單例,不知道什么是雙檢鎖,那這篇文章可能會(huì)幫助到你。懶漢式,線(xiàn)程不安全當(dāng)被問(wèn)到要實(shí)現(xiàn)一個(gè)單例模式時(shí),很多人的第一反應(yīng)是寫(xiě)出如卜的代碼,包括教 科書(shū)上也是這樣教我們的。public class singleton private static singleton instanee;private sing
2、leton () public static singleton getlnstance() if (instance 二二 null) instanee 二 new singleton();rcturn instancc;這段代碼簡(jiǎn)單明了,而h使用了懶加載模式,但是卻存在致命的問(wèn)題。當(dāng)有多個(gè) 線(xiàn)程并行調(diào)用getlnstance0的時(shí)候,就會(huì)創(chuàng)建多個(gè)實(shí)例。也就是說(shuō)在多線(xiàn)程 下不能正常工作。懶漢式,線(xiàn)程安全為了解決上面的問(wèn)題,最簡(jiǎn)單的方法是將整個(gè)getlnstance()方法設(shè)為同步(synchronized)。public static synchronized singleton getln
3、stance() if (instance = null) instance 二 new singleton();return instanee;雖然做到了線(xiàn)程安全,并且解決了多實(shí)例的問(wèn)題,但是它并不高效。因?yàn)樵谌魏?時(shí)候只能有一個(gè)線(xiàn)程調(diào)用gettnstanceo方法。但是同步操作只需耍在第一次 調(diào)用時(shí)才被需要,即第一次創(chuàng)建單例實(shí)例對(duì)象時(shí)。這就引岀了雙重檢驗(yàn)鎖。雙重檢驗(yàn)鎖雙重檢驗(yàn)鎖模式(double checked locking pattern),是一種使用同步塊加鎖 的方法。程序員稱(chēng)其為雙重檢查鎖,因?yàn)闀?huì)有兩次檢查?instance = null, 次是在同步塊外,一次是在同步塊內(nèi)。為什么
4、在同步塊內(nèi)還要再檢驗(yàn)一次?因?yàn)?可能會(huì)有多個(gè)線(xiàn)程一起進(jìn)入同步塊外的if,如果在同步塊內(nèi)不進(jìn)行二次檢驗(yàn)的 話(huà)就會(huì)生成多個(gè)實(shí)例了。/single checked/double checkedpublic static singleton getsingleton() if (instance 二二 null) synchronized (singleton .class) if (instanee = null) instance = new singleton ();return instance ;這段代碼看起來(lái)很完美,很可惜,它是有問(wèn)題。主要在于instance = new singleto
5、n()這句,這并非是一個(gè)原子操作,事實(shí)上在jvm中這句話(huà)大概做了下 面3件事情。1. 給insumce分配內(nèi)存2. 調(diào)用singleton的構(gòu)造函數(shù)來(lái)初始化成員變量3. 將instance對(duì)象指向分配的內(nèi)存空間(執(zhí)行完這步instance就為非null 了) 但是在jvm的即時(shí)編譯器中存在指令重排序的優(yōu)化。也就是說(shuō)上面的第二步和 第三步的順序是不能保證的,最終的執(zhí)行順序可能是1-2-3也可能是1-3-2。 如果是后者,則在3執(zhí)行完畢、2未執(zhí)行之前,被線(xiàn)程二搶占了,這時(shí)instance 已經(jīng)是非null 了(但卻沒(méi)有初始化),所以線(xiàn)程二會(huì)直接返回instance,然 后使用,然后順理成章地報(bào)錯(cuò)。
6、我們只需要將instance變量聲明成volat訂e就可以了。public class singleton private volatile static singleton instance; /聲明成 volati le private singleton () public static singleton getsingleton() if (instanee 二二 null) synchronized (singleton, class) if (instancc = null) instanee = new singleton();rcturn instancc;i有些人認(rèn)為使用v
7、obt訂e的原因是可見(jiàn)性,也就是可以保證線(xiàn)程在本地不會(huì)存 有instance的副本,每次都是去主內(nèi)存小讀取。但其實(shí)是不對(duì)的。使用 volatile的主要原因是其另一個(gè)特性:禁止指令重排序優(yōu)化。也就是說(shuō),在 volatile變量的賦值操作后面會(huì)有一個(gè)內(nèi)存屏障(生成的匯編代碼上),讀操 作不會(huì)被重排序到內(nèi)存屏障之前。比如上面的例子,取操作必須在執(zhí)行完1-2-3 之后或者1-3-2之后,不存在執(zhí)行到1-3然后取到值的情況。從先行發(fā)生原 則的角度理解的話(huà),就是對(duì)于一個(gè)vol at訂c變量的寫(xiě)操作都先行發(fā)生于后而 對(duì)這個(gè)變量的讀操作(這里的“后面”是時(shí)間上的先后順序)。但是特別注意在java 5以前的版
8、本使用了 vobt訂e的雙檢鎖還是有問(wèn)題的。 其原因是java 5以前的jmm (java內(nèi)存模型)是存在缺陷的,即吋將變量聲 明成volatile也不能完全避免重排序,主要是volatile變量前后的代碼仍然 存在重排序問(wèn)題。這個(gè)volatile屏蔽重排序的問(wèn)題在java 5中才得以修復(fù), 所以在這z后才可以放心使用volatile。相信你不會(huì)喜歡這種復(fù)雜乂隱含問(wèn)題的方式,當(dāng)然我們有更好的實(shí)現(xiàn)線(xiàn)程安全的 單例模式的辦法。餓漢式 static final field這種方法非常簡(jiǎn)單,因?yàn)閱卫膶?shí)例被聲明成static和final變量了,在第 一次加載類(lèi)到內(nèi)存屮時(shí)就會(huì)初始化,所以創(chuàng)建實(shí)例本身是線(xiàn)
9、程安全的。public class singleton!類(lèi)加載吋就初始化private static final singleton instance = new singleton();private singleton() public static singleton getlnstance()return instance;這種寫(xiě)法如果完美的話(huà),就沒(méi)必要在啰嗦那么多雙檢鎖的問(wèn)題了。缺點(diǎn)是它不是 一種懶加載模式(lazy initialization),單例會(huì)在加載類(lèi)后一開(kāi)始就被初始 化,即使客戶(hù)端沒(méi)有調(diào)用getlnstance ()方法。餓漢式的創(chuàng)建方式在一些場(chǎng)景中 將無(wú)法使用:譬如s
10、ingleton實(shí)例的創(chuàng)建是依賴(lài)參數(shù)或者配置文件的,在 getlnstance()之前必須調(diào)用某個(gè)方法設(shè)置參數(shù)給它,那樣這種單例寫(xiě)法就無(wú)法 使用了。靜態(tài)內(nèi)部類(lèi) static nested class我比較傾向于使用靜態(tài)內(nèi)部類(lèi)的方法,這種方法也是effective java上所推 薦的。public class singleton private static class singletonllolder private static final singleton instance = new singleton();private singleton () publ ic static fi
11、nal singleton getlnstance() return singletonllolder. instance;這種寫(xiě)法仍然使用jvm木身機(jī)制保證了線(xiàn)程安全問(wèn)題;由于singletonholder 是私有的,除了 getlnstance()之外沒(méi)有辦法訪(fǎng)問(wèn)它,因此它是懶漢式的;同 時(shí)讀取實(shí)例的時(shí)候不會(huì)進(jìn)行同步,沒(méi)有性能缺陷;也不依賴(lài)jdk版本。枚舉enum用枚舉寫(xiě)單例實(shí)在太簡(jiǎn)單了!這也是它最大的優(yōu)點(diǎn)。下面這段代碼就是聲明枚舉 實(shí)例的通常做法。public enum easysingletoninstance;我們可以通過(guò)easysingleton. instance來(lái)訪(fǎng)問(wèn)實(shí)例,這比調(diào)用getlnstance () 方法簡(jiǎn)單多了。創(chuàng)建枚舉默認(rèn)就是線(xiàn)程安全的,所以不需要擔(dān)心double checked locking,而且還能防止反序列化導(dǎo)致重新創(chuàng)建新的對(duì)象。但是還是很少看到冇 人這樣寫(xiě),可能是因?yàn)椴惶煜ぐ伞?偨Y(jié)一般來(lái)說(shuō),單例模式有五種寫(xiě)法:懶漢、餓漢、雙重檢驗(yàn)鎖、靜態(tài)內(nèi)部類(lèi)、枚舉。 上述所說(shuō)都是線(xiàn)程安全的實(shí)現(xiàn),文章開(kāi)頭給岀的第一種方法不算正確的寫(xiě)法。就我個(gè)人而言,一般情況下直接使用餓漢式就好了,如果明確要求要懶加載(lazy initialization)會(huì)傾向丁-使用靜態(tài)內(nèi)部類(lèi),如果涉及到反序列化創(chuàng)建對(duì)象時(shí)會(huì) 試著使用枚舉的方式來(lái)實(shí)現(xiàn)單例。re
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 【正版授權(quán)】 ISO/IEC 19785-3:2025 EN Information technology - Common Biometric Exchange Formats Framework - Part 3: Patron format specifications
- 華科數(shù)控技術(shù)課件網(wǎng)址
- 健康老齡化課件
- 杭州高中模擬數(shù)學(xué)試卷
- 湖南8年級(jí)下冊(cè)數(shù)學(xué)試卷
- 2024-2030年中國(guó)冬棗行業(yè)市場(chǎng)深度分析及發(fā)展趨勢(shì)預(yù)測(cè)報(bào)告
- 2021-2026年中國(guó)EHPS電液泵市場(chǎng)深度分析及投資戰(zhàn)略咨詢(xún)報(bào)告
- 健康科普知識(shí)課件
- 健康科學(xué)減脂課件
- 2023-2028年中國(guó)混合云管理行業(yè)市場(chǎng)全景評(píng)估及投資規(guī)劃建議報(bào)告
- 2025反洗錢(qián)知識(shí)競(jìng)賽題庫(kù)(含答案)
- 實(shí)驗(yàn)室安全 培訓(xùn)
- 2025年天津市中考數(shù)學(xué)真題 (原卷版)
- 民政干部大練兵活動(dòng)方案
- 水泥場(chǎng)地改造方案(3篇)
- DB36∕T 2124-2024 不動(dòng)產(chǎn)登記空間數(shù)據(jù)規(guī)范
- 資材部安全生產(chǎn)責(zé)任制
- 喉水腫病人護(hù)理
- 既有建筑節(jié)能綜合改造項(xiàng)目可行性研究報(bào)告
- 貴州省銅仁市萬(wàn)山區(qū)2024-2025學(xué)年部編版七年級(jí)下學(xué)期6月期末歷史試題(含答案)
- 工廠(chǎng)6S管理培訓(xùn)資料
評(píng)論
0/150
提交評(píng)論