JVM之偏向鎖應用及效能分析
引言: 偏向鎖在JVM中是一個輕量級鎖,本文將分析其原理、應用場景以及在不同的JDK場景下的效能差異,從而讓我們對其有更深的理解。
1. 偏向鎖(Biased Lock)
偏向鎖的目的是為了在無鎖競爭的情況下避免在鎖獲取過程中執行不必要的CAS原子指令;現有的CAS原子指令雖然相對於重量級鎖來說開銷比較小但還是存在非常可觀的本地延遲。而偏向鎖則針對擁有當前鎖的執行緒,允許其在競爭不存在的情況下,直接進入同步的程式碼塊,無需同步操作,從而獲取了相當的效能提升。
2. 原理分析
偏向鎖只需要在置換ThreadID的時候依賴一次CAS原子指令(由於一旦出現多執行緒競爭的情況就必須撤銷偏向鎖,所以偏向鎖的撤銷操作的效能損耗必須小於節省下來的CAS原子指令的效能消耗)。 其實現的細節如下:
- 將物件頭Mark的標記設定為偏向,並將執行緒ID寫入物件頭Mark
- 只要沒有競爭,獲得偏向鎖的執行緒,在將來進入同步塊,不需要做同步
- 當其他執行緒請求相同的鎖時,偏向模式結束
何為物件頭?
在JVM中建立物件時會在物件前面加上兩個字大小的物件頭,在32位機器上一個字為32bit,根據不同的狀態位Mark World中存放不同的內容,如上圖所示在輕量級鎖中,Mark Word被分成兩部分,剛開始時LockWord為被設定為HashCode、最低三位表示LockWord所處的狀態,初始狀態為001表示無鎖狀態。Klass ptr指向Class位元組碼在虛擬機器內部的物件表示的地址。Fields表示連續的物件例項欄位。
我們這裡只需要關心biasable和lightweight locked兩種狀態。在JDK1.6以後預設已經開啟了偏向鎖這個優化,我們可以通過在啟動JVM的時候加上-XX:-UseBiasedLocking引數來禁用偏向鎖(在存在大量鎖物件的建立並高度併發的環境下禁用偏向鎖能夠帶來一定的效能優化)
3. 應用場景
在偏向鎖的應用場景主要集中在競爭不激烈的情況下,通過使用偏向鎖可以減少其在CAS操作下的同步效能消耗,從而獲取效能的提升。關鍵點在於是否存在激烈的鎖競爭,如果存在則不適合使用它。當然了預設情況下,其實被開啟的。
4. 測試程式碼分析
測試使用的程式碼:
測試的情況分析(測試的硬體環境為筆者個人電腦):import java.util.List; import java.util.Vector; public class NonBiasedLockTest { public static List<Integer> numberList = new Vector<Integer>(); public static void main(String[] args) throws InterruptedException { long begin = System.currentTimeMillis(); int count = 0; int startnum = 0; while (count < 10000000) { numberList.add(startnum); startnum += 2; count++; } long end = System.currentTimeMillis(); System.out.println(end - begin); } }
Case 1:
JDK 1.8.0_101
JVM Opts: -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
Time consumed: 1845 ms
Case 2:JDK 1.8.0_101
JVM Opts: -XX:-UseBiasedLocking
Time consumed: 2063 ms
Case 3:JDK 1.7.0_79
JVM Opts: -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
Time consumed: 3916 ms
Case 4:
JDK 1.7.0_79
JVM Opts: -XX:-UseBiasedLocking
Time consumed: 4149 ms
5. 結論分析
在JDK 8的情況下,使用偏向鎖效能提升大約220ms左右,提升量大約10%; 在JDk7的同等情況下, 使用偏向鎖效能提升大約230ms,提升量大約5%。
同樣的設定,在JDK7和JDK8之下,在JDK8之下的效能提升了將近100%,JDK版本的升級對於程式碼效能的提升還是非常顯著的。
6. 參考資料
- http://www.tuicool.com/articles/2aeAZn
- http://www.cnblogs.com/javaminer/p/3889023.html