簡(jiǎn)單來(lái)說(shuō)在JVM中monitorenter和monitorexit字節(jié)碼依賴于底層的操作系統(tǒng)的Mutex Lock來(lái)實(shí)現(xiàn)的,但是由于使用Mutex Lock需要將當(dāng)前線程掛起并從用戶態(tài)切換到內(nèi)核態(tài)來(lái)執(zhí)行,這種切換的代價(jià)是非常昂貴的;然而在現(xiàn)實(shí)中的大部分情況下,同步方法是運(yùn)行在單線程環(huán)境(無(wú)鎖競(jìng)爭(zhēng)環(huán)境)如果每次都調(diào)用Mutex Lock那么將嚴(yán)重的影響程序的性能。不過(guò)在jdk1.6中對(duì)鎖的實(shí)現(xiàn)引入了大量的優(yōu)化,如鎖粗化(Lock Coarsening)、鎖消除(Lock Elimination)、輕量級(jí)鎖(Lightweight Locking)、偏向鎖(Biased Locking)、適應(yīng)性自旋(Adaptive Spinning)等技術(shù)來(lái)減少鎖操作的開(kāi)銷。
鎖粗化(Lock Coarsening):也就是減少不必要的緊連在一起的unlock,lock操作,將多個(gè)連續(xù)的鎖擴(kuò)展成一個(gè)范圍更大的鎖。
鎖消除(Lock Elimination):通過(guò)運(yùn)行時(shí)JIT編譯器的逃逸分析來(lái)消除一些沒(méi)有在當(dāng)前同步塊以外被其他線程共享的數(shù)據(jù)的鎖保護(hù),通過(guò)逃逸分析也可以在線程本地Stack上進(jìn)行對(duì)象空間的分配(同時(shí)還可以減少Heap上的垃圾收集開(kāi)銷)。
輕量級(jí)鎖(Lightweight Locking):這種鎖實(shí)現(xiàn)的背后基于這樣一種假設(shè),即在真實(shí)的情況下我們程序中的大部分同步代碼一般都處于無(wú)鎖競(jìng)爭(zhēng)狀態(tài)(即單線程執(zhí)行環(huán)境),在無(wú)鎖競(jìng)爭(zhēng)的情況下完全可以避免調(diào)用操作系統(tǒng)層面的重量級(jí)互斥鎖,取而代之的是在monitorenter和monitorexit中只需要依靠一條CAS原子指令就可以完成鎖的獲取及釋放。當(dāng)存在鎖競(jìng)爭(zhēng)的情況下,執(zhí)行CAS指令失敗的線程將調(diào)用操作系統(tǒng)互斥鎖進(jìn)入到阻塞狀態(tài),當(dāng)鎖被釋放的時(shí)候被喚醒。
偏向鎖(Biased Locking):是為了在無(wú)鎖競(jìng)爭(zhēng)的情況下避免在鎖獲取過(guò)程中執(zhí)行不必要的CAS原子指令,因?yàn)镃AS原子指令雖然相對(duì)于重量級(jí)鎖來(lái)說(shuō)開(kāi)銷比較小但還是存在非常可觀的本地延遲。
適應(yīng)性自旋(Adaptive Spinning):當(dāng)線程在獲取輕量級(jí)鎖的過(guò)程中執(zhí)行CAS操作失敗時(shí),在進(jìn)入與monitor相關(guān)聯(lián)的操作系統(tǒng)重量級(jí)鎖(mutex semaphore)前會(huì)進(jìn)入忙等待(Spinning)然后再次嘗試,當(dāng)嘗試一定的次數(shù)后如果仍然沒(méi)有成功則調(diào)用與該monitor關(guān)聯(lián)的semaphore(即互斥鎖)進(jìn)入到阻塞狀態(tài)。