JVM鎖優(yōu)化

synchronized重量級(jí)鎖

synchronized是通過(guò)對(duì)象內(nèi)部的一個(gè)叫做監(jiān)視器鎖(monitor)來(lái)實(shí)現(xiàn)的。但是監(jiān)視器鎖本質(zhì)又是依賴于底層的操作系統(tǒng)的Mutex Lock來(lái)實(shí)現(xiàn)的。而操作系統(tǒng)實(shí)現(xiàn)線程之間的切換這就需要從用戶態(tài)轉(zhuǎn)換到核心態(tài),這個(gè)成本非常高,狀態(tài)之間的轉(zhuǎn)換需要相對(duì)比較長(zhǎng)的時(shí)間,這就是為什么synchronized效率低的原因。因此,這種依賴于操作系統(tǒng)Mutex Lock所實(shí)現(xiàn)的鎖我們稱之為“重量級(jí)鎖”。JDK 1.6 后對(duì)synchronized做的種種優(yōu)化,其核心都是為了減少這種重量級(jí)鎖的使用,如適應(yīng)性自旋,鎖清除,鎖粗化,輕量級(jí)鎖,偏向鎖。


自旋鎖

首先是一種鎖,與互斥鎖相似,基本作用是用于線程(進(jìn)程)之間的同步。與普通鎖不同的是,一個(gè)線程A在獲得普通鎖后,如果再有線程B試圖獲取鎖,那么這個(gè)線程B將會(huì)掛起(阻塞);試想下,如果兩個(gè)線程資源競(jìng)爭(zhēng)不是特別激烈,而處理器阻塞一個(gè)線程引起的線程上下文的切換的代價(jià)高于等待資源的代價(jià)的時(shí)候(鎖的已保持者保持鎖時(shí)間比較短),那么線程B可以不放棄CPU時(shí)間片,而是在“原地”忙等,直到鎖的持有者釋放了該鎖,這就是自旋鎖的原理,可見(jiàn)自旋鎖是一種非阻塞鎖(JDK 1.6 中是默認(rèn)開(kāi)啟的)。用戶可以通過(guò)參數(shù)更改:-XX:-UseSpinning來(lái)關(guān)閉。

自旋鎖可能引起的問(wèn)題:自旋鎖雖然避免了線程之間切換的開(kāi)銷,但它是要占CPU時(shí)間的,因此鎖被占用的時(shí)間越短,自旋等待的效果就越好,反之,鎖被占用的時(shí)間很長(zhǎng),那么自旋的線程只會(huì)白白消耗CPU資源。因此自旋等待的時(shí)間必須有一個(gè)限度,如果超過(guò)這個(gè)限度仍然沒(méi)有獲得鎖,就應(yīng)當(dāng)按照傳統(tǒng)方式掛起線程。自旋的次數(shù)默認(rèn)是10,用戶可以通過(guò)參數(shù)更改:-XX:PreBlockSpin=11。

在JDK 1.6 之后引入了自適應(yīng)的自旋鎖。自適應(yīng)意味著自旋的時(shí)間不在固定了,而是由前一次在同一個(gè)鎖上的自旋時(shí)間及鎖的擁有者的狀態(tài)決定的。


鎖清除,鎖粗化

StringBuffer 中的append方法是被synchronized方法修飾的,所以存在鎖。

鎖清除:由于sb是局部變量,所以不會(huì)產(chǎn)生線程安全問(wèn)題,鎖可以被清除


鎖粗化:sb由于多次append,所以鎖可以擴(kuò)展到第一個(gè)append()操作到最后一個(gè)append()操作,只需要加一次鎖




Mark Word

輕量級(jí)鎖

輕量級(jí)是相對(duì)于使用操作系統(tǒng)互斥量來(lái)實(shí)現(xiàn)的傳統(tǒng)鎖而言的。但是,首先需要強(qiáng)調(diào)一點(diǎn)的是,輕量級(jí)鎖并不是用來(lái)代替重量級(jí)鎖的,它的本意是在沒(méi)有多線程競(jìng)爭(zhēng)的前提下,減少傳統(tǒng)的重量級(jí)鎖使用產(chǎn)生的性能消耗。在解釋輕量級(jí)鎖的執(zhí)行過(guò)程之前,先明白一點(diǎn),輕量級(jí)鎖所適應(yīng)的場(chǎng)景是線程交替執(zhí)行同步塊的情況,如果存在同一時(shí)間訪問(wèn)同一鎖的情況,就會(huì)導(dǎo)致輕量級(jí)鎖膨脹為重量級(jí)鎖。

加鎖:

1) 在代碼進(jìn)入同步塊的時(shí)候,如果此對(duì)象沒(méi)有被鎖定(鎖標(biāo)志位為“01”狀態(tài),是否為偏向鎖為“0”),JVM首先在當(dāng)前線程的棧幀建立一個(gè)名為鎖記錄的(Lock Record)的空間,用于存儲(chǔ)對(duì)象當(dāng)前的Mark Word(官方稱之為 Displaced Mark Word)。

2 ) ?JVM使用CAS操作嘗試將對(duì)象的Mark Word 更新為指向Lock Record 的指針。

如果這個(gè)操作成功,那么這個(gè)線程就擁有了該對(duì)象的鎖,并且將對(duì)象的Mark Word 的鎖標(biāo)志位轉(zhuǎn)變?yōu)?00",即表示該對(duì)象處于輕量級(jí)鎖狀態(tài)。


如果這個(gè)更新操作失敗了,虛擬機(jī)首先會(huì)檢查對(duì)象的Mark Word是否指向當(dāng)前線程的棧幀,如果是就說(shuō)明當(dāng)前線程已經(jīng)擁有了這個(gè)對(duì)象的鎖,那就可以直接進(jìn)入同步塊繼續(xù)執(zhí)行。否則說(shuō)明多個(gè)線程競(jìng)爭(zhēng)鎖,輕量級(jí)鎖就要膨脹為重量級(jí)鎖,鎖標(biāo)志的狀態(tài)值變?yōu)椤?0”,Mark Word中存儲(chǔ)的就是指向重量級(jí)鎖(互斥量)的指針,后面等待鎖的線程也要進(jìn)入阻塞狀態(tài)。

解鎖:

1)通過(guò)CAS操作嘗試把線程中復(fù)制的Displaced Mark Word對(duì)象替換當(dāng)前的Mark Word。

2)如果替換成功,整個(gè)同步過(guò)程就完成了。

3)如果替換失敗,說(shuō)明有其他線程嘗試過(guò)獲取該鎖(此時(shí)鎖已膨脹),那就要在釋放鎖的同時(shí),喚醒被掛起的線程。


偏向鎖

偏向鎖的“偏”,就是偏心的“偏”,它的意思就是這個(gè)鎖會(huì)偏向于第一個(gè)獲取它的線程,如果在接下來(lái)的執(zhí)行過(guò)程中,該鎖沒(méi)有被其他線程獲取,則持有偏向鎖的線程永遠(yuǎn)不需要再進(jìn)行同步。

引入偏向鎖是為了在無(wú)多線程競(jìng)爭(zhēng)的情況下盡量減少不必要的輕量級(jí)鎖執(zhí)行路徑,因?yàn)檩p量級(jí)鎖的獲取及釋放依賴多次CAS原子指令,而偏向鎖只需要在置換Thread ID的時(shí)候依賴一次CAS原子指令(由于一旦出現(xiàn)多線程競(jìng)爭(zhēng)的情況就必須撤銷偏向鎖,所以偏向鎖的撤銷操作的性能損耗必須小于節(jié)省下來(lái)的CAS原子指令的性能消耗)。輕量級(jí)鎖是為了在線程交替執(zhí)行同步塊時(shí)提高性能,而偏向鎖則是在只有一個(gè)線程執(zhí)行同步塊時(shí)進(jìn)一步提高性能。

當(dāng)有另外一個(gè)線程去嘗試獲取這個(gè)鎖時(shí),偏向模式就宣告結(jié)束。根據(jù)鎖對(duì)象目前是否處于被鎖定的狀態(tài),撤銷偏向(Revoke Bias)后恢復(fù)到未鎖定(標(biāo)志位為01)或者輕量級(jí)鎖(標(biāo)志位為00)的狀態(tài),后續(xù)的同步操作就如輕量級(jí)鎖那樣執(zhí)行。轉(zhuǎn)換圖:

參考:

http://blog.csdn.net/truong/article/details/74942155

http://blog.csdn.net/truong/article/details/74941345

http://blog.csdn.net/hsuxu/article/details/9472389

http://blog.csdn.net/hsuxu/article/details/9472381

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

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

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