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