Java輕量級鎖原理詳解(Lightweight Locking)

你們知道,Java的多線程安全是基於Lock機制實現的,而Lock的性能每每不如人意。
緣由是,monitorenter與monitorexit這兩個控制多線程同步的bytecode原語,是JVM依賴操做系統互斥(mutex)來實現的。
互斥是一種會致使線程掛起,並在較短的時間內又須要從新調度回原線程的,較爲消耗資源的操做。 安全

爲了優化Java的Lock機制,從Java6開始引入了輕量級鎖的概念。 多線程

輕量級鎖(Lightweight Locking)本意是爲了減小多線程進入互斥的概率,並非要替代互斥。
它利用了CPU原語Compare-And-Swap(CAS,彙編指令CMPXCHG),嘗試在進入互斥前,進行補救。 性能

本文將詳細介紹JVM如何利用CAS,實現輕量級鎖。 優化

 

原理詳解

Java Object Model中定義,Object Header是一個2字(1 word = 4 byte)長度的存儲區域。
第一個字長度的區域用來標記同步,GC以及hash code等,官方稱之爲 mark word。第二個字長度的區域是指向到對象的Class。 spa

在2個word中,mark word是輕量級鎖實現的關鍵。它的結構見下表 操作系統

從表中能夠看到,state爲lightweight locked的那行即爲輕量級鎖標記。bitfieds名爲指向lock record的指針,這裏的lock record,實際上是一塊分配在線程堆棧上的空間區域
用於CAS前,拷貝object上的mark word(爲何要拷貝,請看下文)。
第三項是重量級鎖標記。後面的狀態單詞頗有趣,inflated,譯爲膨脹,在這裏意思實際上是鎖已升級到OS-level。
在本文的範圍內,咱們只關注第二和第三項便可。 線程

爲了能直觀的理解lock,unlock與mark word之間的聯繫,我畫了一張流程圖: 指針

在圖中,提到了拷貝object mark word,因爲脫離了原始mark word,官方將它冠以displaced前綴,即displaced mark word(置換標記字)。
這個displaced mark word是整個輕量級鎖實現的關鍵,在CAS中的compare就須要用它做爲條件。 code

爲何要拷貝mark word?
其實很簡單,緣由是爲了避免想在lock與unlock這種底層操做上再加同步。 對象

在拷貝完object mark word以後,JVM作了一步交換指針的操做,即流程中第一個橙色矩形框內容所述。
將object mark word裏的輕量級鎖指針指向lock record所在的stack指針,做用是讓其餘線程知道,該object monitor已被佔用。
lock record裏的owner指針指向object mark word的做用是爲了在接下里的運行過程當中,識別哪一個對象被鎖住了。

下圖直觀地描述了交換指針的操做。

exchange_pointer_1

最後一步unlock中,咱們發現,JVM一樣使用了CAS來驗證object mark word在持有鎖到釋放鎖之間,有無被其餘線程訪問。 若是其餘線程在持有鎖這段時間裏,嘗試獲取過鎖,則可能自身被掛起,而mark word的重量級鎖指針也會被相應修改。 此時,unlock後就須要喚醒被掛起的線程。

相關文章
相關標籤/搜索