HotSpot中的幾種鎖優化技術
在JDK 1.6中,HotSpot虛擬機器實現不少鎖優化技術來提高程式的執行效率。
自旋鎖
自旋鎖可以使執行緒在沒有取得鎖的時候不被掛起,而轉去執行一個空迴圈。這樣可以避免執行緒切換的開銷,在鎖被佔用時間很短時對效能有所提高。反之,如果鎖佔用時間過長,那麼自旋的執行緒只會白白消耗處理器資源。在jdk 1.6中還引入了自適應的自旋鎖,即鎖的自旋次數不在固定,而是根由前一次在同一個鎖的自旋時間及鎖的擁有者的狀態來決定。
偏向鎖
這是JDK 1.6引入的一項鎖優化技術,其核心思想是,在無競爭的情況下,取消之前已經取得鎖的執行緒同步操作。其過程為,當鎖物件第一次被執行緒獲取的時候,虛擬機器將會把物件頭中的標誌位設為"01",即偏向模式,同時使用CAS操作把獲取到這個鎖的執行緒的ID記錄在物件的Mark Word之中,如果CAS操作成功,持有偏向鎖的執行緒以後每次進入這個鎖相關的同步塊時,虛擬機器都可以不再進行任何同步操作。
在HotSpot虛擬機器中,物件表示被設計為一個OOP-Klass模型,其中OOP指的是Ordinary Object Pointer,用來表示物件的例項資訊,而Klass則包含元資料和方法資訊,用來描述類。Klass是在類載入時在方法區建立,表示其元資料(欄位、方法等)。
而我們這裡要重點講的是OOP物件,其包含兩部分:物件頭、例項物件和對齊填充。物件頭又分兩部分:
- Mark Word,用於儲存物件自身的執行時資料,如雜湊碼,GC分代年齡等,是實現偏向鎖和輕量級鎖的關鍵
- 元資料指標,用於儲存指向方法區instanceKlass例項,如果是陣列物件的話,還會有一個額外的部分用於儲存陣列長度
注2:CAS(compare and swap)
CAS是設計併發演算法時用到的一種技術,簡單來說,就是在更新值前進行一次比較,比較結果正確後才進行賦值。
CAS指令需要有3個運算元,分別是記憶體位置(java中可簡單理解為變數的記憶體地址,用V表示)、舊的預期地址(用A表示)和新值(用B)表示。CAS指令執行時,當且僅當V符合舊預期值A時,處理器用新值B更新V的值,否則它就不更新,但是無論是否更新了V的值,都會返回V的舊值,上述操作是一個原子操作。
輕量級鎖
這也是JDK 1.6引入的新型鎖機制。它的本意是在沒有多執行緒競爭的前提下,減少傳統的重量級鎖使用作業系統互斥量產生的效能消耗。即當另一個執行緒去嘗試獲取處於偏向模式的鎖時,偏向模式就宣告結束了。Java虛擬機器就會讓執行緒申請輕量級鎖。
其過程如下:在程式碼進入同步塊時,如果此同步物件沒有被鎖定,虛擬機器首先將在當前執行緒的棧幀中建立一個名為鎖記錄(Lock Record)的空間,用於儲存Mark Word的拷貝。然後,虛擬機器將使用CAS操作嘗試將物件的Mark Word更新為指向Lock Record的指標。如果這個更新動作成功了,那麼這個執行緒就擁有了該物件的鎖,並且物件Mark Word的鎖標誌位將變成"00",即表示此物件處於輕量級鎖狀態。
輕量級鎖使用CAS操作避免了使用互斥量的開銷,但如果存在鎖競爭,除了互斥量的開銷外,還額外發生了CAS操作,因此,在此情景下,輕量級鎖會比傳統的重量級鎖更慢。
鎖消除及鎖粗化
鎖消除是指虛擬機器即時編譯器在執行時,對一些程式碼上要求同步,但是被檢測到不可能存在共享資料競爭的鎖進行消除。如:在單執行緒中使用jdk提供的執行緒安全的類。
鎖粗化是指如果虛擬機器探測到有這樣一串零碎的操作都是對同一個物件加鎖,為了避免頻繁地進行互斥同步操作造成的效能損耗,將會把加鎖同步的範圍擴充套件(粗化)到整個操作序列的外部。
參考:《深入理解Java虛擬機器》