分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程
1. 對象內(nèi)部結(jié)構(gòu)
一個對象內(nèi)部結(jié)構(gòu)由對象頭、實例成員以及對齊填充組成。其中對象頭由64位的Mark Word以及元數(shù)據(jù)指針和數(shù)組長度(只有數(shù)組對象才有)組成,其中元數(shù)據(jù)指針指向的是元空間中該對象的類.class。其中Mark Word包括一位偏向狀態(tài)和兩位鎖狀態(tài)標(biāo)志,如下圖。
?
2. 內(nèi)部結(jié)構(gòu)查看
2.1 jor-core插件下載
首先,我們?nèi)aven倉庫下載一個jol-core插件或者在pom.xml中配置一下依賴,我這邊使用的是IDEA2020版,所以下載了2020年的一個版本,如下圖。
?
?
2.2 對象內(nèi)部結(jié)構(gòu)分析
2.2.1 不是數(shù)組對象,而且有填充補齊位。填充補齊位為了湊成8個字節(jié),64位,方便64位系統(tǒng)尋址。
2.2.2 不是數(shù)組對象,且沒有填充補齊位
2.2.3 數(shù)組對象
?
3. 鎖升級或降級過程的鎖標(biāo)志位
3.1 偏向鎖的啟用和延時
3.1.1 偏向鎖是否啟用,可通過-XX:+UseBiasedLocking開啟偏向鎖以及-XX:-UseBiasedLocking關(guān)閉偏向鎖;偏向鎖啟動延時時間,可通過-XX:BiasedLockingStartupDealy變量設(shè)置時間,ms為單位。通過?java -XX:+PrintFlagsFinal -version | findstr "BiasedLocking" 可查看java關(guān)于偏向鎖的默認(rèn)設(shè)置,如下圖。
3.1.2 啟動偏向鎖,并設(shè)定偏向鎖啟動延遲時間為4s,如下圖。
3.2 偏向鎖升級、膨脹過程(本節(jié)操作都是在開啟偏向鎖,而且延時為0的場景下)
3.2.1 升級為偏向鎖,高位的三位鎖標(biāo)志是101(帶線程id);釋放鎖不會降級。
3.2.2 升級為輕量級鎖,高位的鎖標(biāo)志是兩位00。如果搶鎖的線程和對象頭內(nèi)偏向鎖記錄的線程不一致時,升級為輕量級鎖;
注意,其它博客提到的這么一句話:如果偏向鎖的那個偏向線程不存在,鎖不升級。經(jīng)過實踐,仍然還是升級為輕量級鎖了!!!
3.2.3 再次搶鎖時,直接從無鎖狀態(tài)變?yōu)檩p量級鎖,然后釋放鎖又降級為無鎖狀態(tài)
3.2.4 只要兩個線程同時爭搶,那么線程直接就升級為重量級鎖,不管原先是什么鎖狀態(tài);而且釋放鎖后,也不會降級。
這邊需要提一下Lock Record,每一個線程在搶鎖時,都會先在線程的棧幀中創(chuàng)建存儲Lock Record的空間(存儲共享對象的Mark Word的拷貝);然后每個線程搶鎖時都會嘗試將共享對象的Mark Word指向自己的Lock Record。最終,共享對象的Mark Word會存儲搶鎖成功線程的Lock Record地址;那些搶鎖失敗的線程會CAS自旋一定次數(shù),如果在指定次數(shù)內(nèi)成功了(默認(rèn)10次),那么就更改共享對象的Mark Word;如果指定次數(shù)后仍不成功,就將鎖升級為重量級鎖了。
?
附錄
最終出現(xiàn)了一個問題,系統(tǒng)開啟偏向鎖,兩個線程間隔100ms搶鎖后都是偏向鎖,第二個線程搶鎖沒有升級為輕量級鎖;而且兩次對象頭內(nèi)容都一樣,為什么???
當(dāng)兩個線程搶鎖的時間間隔改為20ms,鎖升級變化過程又正常了。
總結(jié)
以上是生活随笔為你收集整理的分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java虚拟机JVM常用的几种回收算法和
- 下一篇: Java常用分析工具Jps、Jstat、