溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

double-checked locking與單例模式的示例分析

發(fā)布時(shí)間:2021-12-23 16:47:05 來(lái)源:億速云 閱讀:122 作者:柒染 欄目:大數(shù)據(jù)

本篇文章為大家展示了double-checked locking與單例模式的示例分析,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。

單例模式確保某個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。在計(jì)算機(jī)系統(tǒng)中,線程池、緩存、日志對(duì)象、對(duì)話框、打印機(jī)、顯卡的驅(qū)動(dòng)程序?qū)ο蟪1辉O(shè)計(jì)成單例。

單例模式有如下實(shí)現(xiàn)方式:

double-checked locking與單例模式的示例分析

這種方式稱為延遲初始化,但是在多線程的情況下會(huì)失效,于是使用同步鎖,給getInstance() 方法加鎖:

double-checked locking與單例模式的示例分析

同步是需要開(kāi)銷的,我們只需要在初始化的時(shí)候同步,而正常的代碼執(zhí)行路徑不需要同步,于是有了雙重檢查加鎖(DCL):

double-checked locking與單例模式的示例分析

這樣一種設(shè)計(jì)可以保證只產(chǎn)生一個(gè)實(shí)例,并且只會(huì)在初始化的時(shí)候加同步鎖,看似精妙絕倫,但卻會(huì)引發(fā)另一個(gè)問(wèn)題,這個(gè)問(wèn)題由指令重排序引起。

指令重排序是為了優(yōu)化指令,提高程序運(yùn)行效率。指令重排序包括編譯器重排序和運(yùn)行時(shí)重排序。JVM規(guī)范規(guī)定,指令重排序可以在不影響單線程程序執(zhí)行結(jié)果前提下進(jìn)行。例如 instance = new Singleton() 可分解為如下偽代碼:

double-checked locking與單例模式的示例分析

但是經(jīng)過(guò)重排序后如下:

double-checked locking與單例模式的示例分析

將第2步和第3步調(diào)換順序,在單線程情況下不會(huì)影響程序執(zhí)行的結(jié)果,但是在多線程情況下就不一樣了。線程A執(zhí)行了instance = memory(這對(duì)另一個(gè)線程B來(lái)說(shuō)是可見(jiàn)的),此時(shí)線程B執(zhí)行外層 if (instance == null),發(fā)現(xiàn)instance不為空,隨即返回,但是得到的卻是未被完全初始化的實(shí)例,在使用的時(shí)候必定會(huì)有風(fēng)險(xiǎn),這正是雙重檢查鎖定的問(wèn)題所在!

鑒于DCL的缺陷,便有了修訂版:

double-checked locking與單例模式的示例分析

修訂版試圖引進(jìn)局部變量和第二個(gè)synchronized來(lái)解決指令重排序的問(wèn)題。但是,Java語(yǔ)言規(guī)范雖然規(guī)定了同步代碼塊內(nèi)的代碼必須在對(duì)象鎖釋放之前執(zhí)行完畢,卻沒(méi)有規(guī)定同步代碼塊之外的代碼不能在對(duì)象鎖釋放之前執(zhí)行,也就是說(shuō) instance = temp 可能會(huì)在編譯期或者運(yùn)行期移到里層的synchronized內(nèi),于是又會(huì)引發(fā)跟DCL一樣的問(wèn)題。

在JDK1.5之后,可以使用volatile變量禁止指令重排序,讓DCL生效:

double-checked locking與單例模式的示例分析

volatile的另一個(gè)語(yǔ)義是保證變量修改的可見(jiàn)性。

單例模式還有如下實(shí)現(xiàn)方式:

double-checked locking與單例模式的示例分析

這種方式稱為延遲初始化占位(Holder)類模式。該模式引進(jìn)了一個(gè)靜態(tài)內(nèi)部類(占位類),在內(nèi)部類中提前初始化實(shí)例,既保證了Singleton實(shí)例的延遲初始化,又保證了同步。這是一種提前初始化(惡漢式)和延遲初始化(懶漢式)的綜合模式。

至此,正確的單例模式有三種實(shí)現(xiàn)方式:

1.提前初始化。

double-checked locking與單例模式的示例分析

2.雙重檢查鎖定 + volatile。

3.延遲初始化占位類模式。

上述內(nèi)容就是double-checked locking與單例模式的示例分析,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI