Synchronized 鎖升級

Synchronized是JAVA鎖的一種形式,是基於JVM層面進行實現。主要有兩種用法

  • 修飾方法
    • 在實現時,class文件有特殊標識符ACC_SYNCHRONIZED作用於同步方法
  • 修飾代碼塊
    • 在實現時,class文件會有兩條指令monitorenter及monitorexit,作用於代碼塊之間

在jdk6之後Synchrozied 升級了,具有多種鎖的形式,偏向鎖,輕量級鎖,自旋鎖,及重量級鎖。這幾種鎖之間是隻升不降。

即偏向鎖可以升級爲輕量級鎖,但是輕量級鎖不能降低爲偏向鎖。接下來我們來看看鎖是怎麼升級的。

首先來看看一個作用於Synchronized對象是怎麼表示"被獲得鎖的",主要是用對象頭的32個字節來標識的。接下來我們借用一張圖,來看看對象頭。

當鎖處於不同時期的時候,這32個字節所存在的內容也是不一樣的。

當一個線程要獲得鎖的時候,是從偏向鎖開始的。首先判斷該對象頭是否處於無鎖狀態或者偏向鎖狀態,如果是則利用CAS操作將對象頭的線程ID替換爲當前ID,如果CAS操作成功,則代表獲得偏向鎖。如果失敗則證明當前偏向鎖被其他線程獲得,需要注意的是偏向鎖並不會主動釋放,所以我們先看看獲得該鎖的線程是否存活,如果死了,就想鎖置爲無鎖狀態或者指向當前線程,如果線程存活,我們就去該線程的棧中看看鎖記錄是否還需要佔用當前鎖(這一步是我認爲的),如果不佔用,那還是置爲無鎖狀態或者指向當前線程。如果佔用,jvm 會再安全點釋放偏向鎖,並升級爲輕量級鎖。

當線程獲得輕量級鎖時,首先會將對象頭的markword字段複製到本線程的棧幀的鎖記錄空間中,並利用cas操作將原markword改爲鎖記錄空間的指針,當線程2通過cas操作失敗時,則先自旋一段時間。若通過多次自旋依然失敗,則鎖升級爲重量級鎖。

至於重量級鎖,我覺得就是類似於AQS的雙向隊列,有一個監視器,他有一個隊列,保存需要該鎖的線程。

從偏向鎖,輕量級鎖,自選旋,到重量級鎖。其實是鎖不斷升級優化的過程。偏向鎖適用於大部份時間只有一個線程的場景,其消耗最小。

有一點題外話記錄一下:synchronized是確保了在獲取鎖和釋放鎖的時候都有內存屏障,且數據一定會從主內存中重新load或者store到主內存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章