最近在看OpenJdk的源碼,對對象頭部分有了一個更直觀的理解。同時,對象頭中的MarkWord部分,又包含了對不同鎖狀態的標識,故以此爲起點,梳理下不同鎖狀態的表示及不同鎖狀態的轉換。
1、對象頭
JVM內部,使用 OOP-Klass 二分模型來表示類和對象,OOP用來表示Java對象實例,Klass用來表示Java類。在Java應用程序運行過程中,每創建一個Java對象,在JVM內部就會相應地創建一個OOP對象來對應(具體爲instanceOopDesc對象)。而每加載一個Java類,也會對應創建一個Klass對象來對應(具體爲instanceKlass對象)。
Java對象在內存中的佈局,可分爲連續的兩部分:instanceOopDesc + 實例數據。數組對象爲:arrayOopDesc + 實例數據。
這裏的 instanceOopDesc 與 arrayOopDesc,即爲對象頭。對象頭中的Mark Word,即 OopDesc 基類中的 _mark 成員,存儲對象運行時信息,如Hash Code、Age、鎖狀態標識、線程持有的鎖、偏向線程ID、偏向時間戳等。對象頭中的元數據指針,即 OopDesc 基類中的 _metadata 成員,指向描述對象所對應 Java 類的 Klass 對象。
2、鎖狀態
目前 Synchronized 鎖狀態有四種,級別從低到高分別是:無所、偏向鎖、輕量級鎖和重量級鎖。對應到 Mark Word 裏,就如下圖所示:
對象狀態 | 25bit | 4bit | 1bit | 2bit | |
23bit | 2bit | 是否偏向鎖 | 鎖標識 | ||
Unlocked | Hashcode | Age | 0 | 01 | |
Light-weight locked | 鎖記錄指針 | 00 | |||
Heavy-weight locked | Monitor指針 | 10 | |||
Mraked for GC | Forward指針 | 11 | |||
Biased/biasable | 線程ID | Epoch | Age | 1 | 01 |
3、鎖狀態轉換
無鎖:
偏向鎖:
輕量級鎖:
重量級鎖: