Java多執行緒優化之偏向鎖原理分析
本文來自Ken Wu's Blog,原文標題:《Java偏向鎖實現原理(Biased Locking)》
閱讀本文的讀者,需要對Java輕量級鎖有一定的瞭解,知道lock record, mark word之類的名詞。
Java偏向鎖(Biased Locking)是Java 6引入的一項多執行緒優化。它通過消除資源無競爭情況下的同步原語,進一步提高了程式的執行效能。
輕量級鎖也是一種多執行緒優化,它與偏向鎖的區別在於,輕量級鎖是通過CAS來避免進入開銷較大的互斥操作,而偏向鎖是在無競爭場景下完全消除同步,連CAS也不執行(CAS本身仍舊是一種作業系統同步原語,始終要在JVM與OS之間來回,有一定的開銷)。
所謂的無競爭場景,舉個例子,就是單執行緒訪問帶同步的資源或方法。
偏向鎖實現原理
偏向鎖,顧名思義,它會偏向於第一個訪問鎖的執行緒,如果在接下來的執行過程中,該鎖沒有被其他的執行緒訪問,則持有偏向鎖的執行緒將永遠不需要觸發同步。
如果在執行過程中,遇到了其他執行緒搶佔鎖,則持有偏向鎖的執行緒會被掛起,JVM會嘗試消除它身上的偏向鎖,將鎖恢復到標準的輕量級鎖。(偏向鎖只能在單執行緒下起作用)
通過下圖可以更直觀的理解偏向鎖:
這張圖,省略了輕量級鎖相關的幾處步驟,將關注點更多地聚焦在偏向鎖的狀態變化上。
偏向模式和非偏向模式,在下面的mark word表中,主要體現在thread ID欄位是否為空。
掛起持有偏向鎖的執行緒,這步操作類似GC的pause,但不同之處是,它只掛起持有偏向鎖的執行緒(非當前執行緒)。
在搶佔模式的橙色區域說明中有提到,指向當前堆疊中最近的一個lock record(在輕量級鎖原理一文有講到,lock record是進入鎖前會在stack上建立的一份記憶體空間)。這裡提到的最近的一個lock record,其實就是當前鎖所在的stack frame上分配的lock record。
整個步驟是從偏向鎖恢復到輕量級鎖的過程。
偏向鎖也會帶來額外開銷
在JDK6中,偏向鎖是預設啟用的。它提高了單執行緒訪問同步資源的效能。
但試想一下,如果你的同步資源或程式碼一直都是多執行緒訪問的,那麼消除偏向鎖這一步驟對你來說就是多餘的。事實上,消除偏向鎖的開銷還是蠻大的。
所以在你非常熟悉自己的程式碼前提下,大可禁用偏向鎖 -XX:-UseBiasedLocking 。