java完美單列模式-雙重檢查模式詳解

首先廢話不多說直接上代碼


完整代碼

相信很多人知道是這樣但是并不一定知道為什么,知其然不知其所以然

下面來一層層講解

1、首先開一個(gè)簡單粗暴的

圖1

? ? ? 如果單列模式能寫成這樣也真是無語了,此處省去100000字,這里的問題在于沒有做任何并發(fā)的處理,你至少得價(jià)格同步鎖啊。好吧我們來加一個(gè)同步鎖。

圖2


好了同步鎖加上了,還有問題嗎?當(dāng)然了問題還是有的,不然我還講什么呢,哈哈

很明顯的問題就是同步(synchronized)會有一個(gè)效率問題,假如有100個(gè)線程同時(shí)獲取這個(gè)實(shí)例,第一個(gè)線程進(jìn)來獲取鎖其他99個(gè)線程只能等待,當(dāng)然第一次獲取只能這樣,但是當(dāng)instance不為null的時(shí)候,其實(shí)已經(jīng)不需要在經(jīng)過同步鎖這一步,只需要直接返回這個(gè)實(shí)例就好,所以在同步代碼塊的外層再加一個(gè)判斷instance是否為空,上代碼

圖3

現(xiàn)在雙重判斷,那么問題解決了嗎,我告訴你還沒有,那么問題出在哪里呢?問題就在?instance=newSingleton();

這并非是一個(gè)原子操作,在jvm中這句話做了以下三件事情

1、給instance分配內(nèi)存

2、調(diào)用Singleton的構(gòu)造函數(shù),初始化成員變量

3、將instance對象指向內(nèi)存分配的空間(這一步執(zhí)行完畢instance就為非空了)

理想的狀態(tài)就是1-2-3順序執(zhí)行,但是事實(shí)并不是如此,因?yàn)閖vm中存在指令重排優(yōu)化,簡單來說1-2-3并不一定是順序執(zhí)行的,也可能是1-3-2,如果是這樣在執(zhí)行完3步驟后, 2還沒有執(zhí)行,此時(shí)instance已經(jīng)不為null,但是還沒有初始化,也在此時(shí)其它線程進(jìn)來了判斷instance != null,獲取實(shí)例并使用,順理成章的就報(bào)錯(cuò)了。那么怎么解決呢-----volatile出場了,volatile保證了變量的可見性和有序性(解決了上面的問題)

總結(jié):這個(gè)單列模式用了兩個(gè)判斷和兩種鎖,說說這兩種鎖的區(qū)別synchronized和volatile

volatile相對于synchronized輕量級一點(diǎn),也就是效率更好,因?yàn)闆]有線程等待(但是volatile并不能取代synchronized)

volatile不具備原子性,所以不能取代synchronized

volatile實(shí)現(xiàn)原理將會在下回分解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容