【Java】嘮嘮synchronized中的輕量級鎖


  • 說到輕量級鎖,我們必須先說一下輕量級鎖是什么?

synchronized在JDK1.6之后的優化鎖后,一共有四種鎖階段:

無鎖 --> 偏向鎖 --> 輕量級鎖 --> 重量級鎖

而輕量級鎖,正處於是第三種階段。

 

 

 

那么如何才會觸發偏向鎖升級為輕量級鎖?偏向鎖又是如何升級為輕量級鎖的呢?

 

 

 

 

 1》如何觸發偏向鎖升級為輕量級鎖呢?

①線程A此時已占有鎖對象資源,鎖對象【Mark Word】中線程ID指向線程A;

②線程B此時訪問同步代碼塊,試圖搶占資源,通過CAS修改Mard Word,但由於線程A已占有鎖對象資源,

此時CAS修改失敗;

③那么此時將會觸發偏向鎖升級為輕量級鎖

 

2》偏向鎖在升級為輕量級鎖時,會先撤銷偏向鎖,那么是如何撤銷的呢?

①首先等線程A在安全節點阻塞(類似於GC前線程在安全節點阻塞);

②判斷線程A是否還存活,如果線程A還存活;

③判斷線程A是否繼續競爭鎖,如果不競爭,線程B獲得偏向鎖;

④如果競爭,則線程A和線程B同時升級為搶占輕量級鎖

 

 

 

  • synchronized和對象表頭(即Mark Word)的關系可以說是息息相關,那么我們先看一下各個鎖級別表頭情況:

 

 

 

 

 

  • 由與輕量級鎖的Mark Word只剩下了【指向線程棧中鎖記錄的指針】和【鎖標志位】,那么具體是什么格式呢?

 

 

大致流程是這樣:

1》偏向鎖撤銷之后(偏向狀態為0),現在無論是A線程還是B線程執行同步代碼塊進行加鎖,都在自己的線程幀棧中創建一個鎖記錄【Lock Record】;

2》線程A此時搶占鎖,將Object中的【Mark Word】拷貝到線程棧中的【Lock Record】中的【displaced hdr】;

3》將鎖記錄中的【owner】指針指向加鎖的對象;

4》將鎖對象的對象頭【Mard Word】替換為鎖記錄的指針;

5》此時鎖標志位是00,為輕量級鎖。

 

 

 

 

  • 那么我看下如下代碼,synchronized又是如何實現可重入的呢?
synchronized(obj){
    synchronized(obj){ //①
        synchronized(obj){ 
        }
    }
}

 

synchronized在輕量級鎖上的重入原理可以這樣理解:

線程棧中有一個初始的【Lock Record】,其中【displaced hdr】是從【Mard Word】中拷貝出來的,

當代碼執行到①處時,此時會向線程棧中添加一個【displaced hdr】為NULL的【Lock Record】,

如果繼續使用synchronized進行重入時,會繼續向線程棧中添加【displaced hdr】為NULL的【Lock Record】對象。

 

 

 

 

 

釋放鎖的原理我腳的大家應該猜到了,就是像棧一樣,從下至上每次排出一個【Lock Record】。

 

 

 

  • 輕量級鎖解鎖過程是個什么樣的呢?

當線程在輕量級鎖解鎖過程,先通過CAS將線程棧中鎖記錄【Lock Record】的【Diplaced Header】,

替換至鎖對象中。

若替換成功,說明線程已經執行完同步代碼塊,該期間沒有任何多余線程進行競爭,輕量級鎖解鎖。

若替換失敗,說明線程還未執行完同步代碼塊,若此時鎖對象資源仍存在競爭,並有其他線程加入競爭,則鎖將膨脹至重量級鎖。

 

 

 

  • 輕量級鎖的優缺點

輕量級鎖優點主要是采用自旋的方式來處理線程競爭的,自旋操作可以避免線程阻塞、喚醒等操作,從而減少線程上下文切換而對服務器性能的消耗。

不過如果存在某線程占用鎖資源時間過長,從而導致其他線程長時間處於自旋狀態,會嚴重消耗CPU資源,使得CPU使用率飆升,

所以此時需要引入重量級鎖,來達到服務器性能上的平衡。

 

 

 

了解其他:

Sychronized底層加鎖原理詳解 》

從synchronized鎖優化來了解自適應自旋鎖、鎖消除和鎖粗化 》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM