鎖優化的過程:無鎖->偏向鎖->輕量級鎖->重量級鎖
假設許多存在數據競爭的情形都是一個線程執行完同步代碼后,另外一個線程才開始競爭鎖;
問題1 如何獲取輕量級鎖?
沒有引入偏向鎖的情形
當線程T1請求對象鎖,即JVM執行monitorenter
字節碼指令時,
如果最初對象鎖處于無鎖狀態unlocked
,即共享對象頭mark word
的tag bits
值為01
,偏向模式標記位是0
,
首先,在線程T1的私有棧中分配lock record
;
此時,lock record
由兩部分組成:displaced hdr
和owner
;
然后復制共享對象頭此時的mark record
值到lock record
的displaced hdr
,使得owner
指針指向共享對象的內存地址;
接著,嘗試使用CAS
設置共享對象頭mark word
指向線程T1的lock record
;
此時必操作成功,因為此時只有線程T1在請求鎖,則設置共享對象頭mark word
的tag bits
值為00
,線程T1獲得輕量級鎖,開始執行同步代碼;
當T1執行完同步代碼,執行monitorexit
釋放鎖時,嘗試使用CAS
操作設置共享對象頭mark word
指向線程T1的lock record
,
如果成功,則說明并沒有其他線程來競爭對象鎖,對象鎖仍處于輕量級狀態lightweight locked
;
如果失敗,則說明在線程T1還持有輕量級鎖時,有其他線程在競爭對象鎖,然后才去一種比較慢的合理方式釋放T1持有的輕量級鎖,同時通知處于等待的線程去競爭獲取鎖。
如果共享對象處于輕量級鎖狀態lightweight locked
,即共享對象頭mark word
的tag bits
值為00
,即有線程T1已經獲得輕量級鎖,在執行同步代碼,現在線程T2也開始請求對象鎖了,則線程T2嘗試使用CAS
競爭設置共享對象頭mark word
指向線程T2的lock record
,
如果失敗,則表明線程T1還持有鎖,還在臨界區域內,就將輕量級鎖膨脹為重量級鎖;
如果成功,則表示線程T1已經釋放鎖了,退出臨界區域了,否則可能出現兩個線程同時進入臨界區域,不滿足鎖的排他性;線程T2開始執行同步代碼;
問題2:輕量級鎖是如何處理鎖重入情形的?
首先,判斷對象鎖是否處于輕量級狀態;如果是,則接著判斷對象頭mark word 記錄的lock record 是否指向當前線程的;如果是,則在前述lock record中壓入一個0值。這樣是為了方便重入輕量級鎖的釋放,因為當釋放輕量級鎖時,如果對象頭mark word指向的地址記錄一個0值,就可以知道是重入輕量級鎖釋放鎖了,直接釋放,不需要更新對象頭mark word。這里也是sun公司的hotspot提供的不同于其他虛擬機的輕量級鎖優化。
問題3:輕量級鎖如何升級為重量級鎖?