第16講 synchronized底層如何實現 什麼是鎖的升級降級

第16講 | synchronized底層如何實現?什麼是鎖的升級、降級?

synchronized代碼塊是由一對兒monitorenter/monitorexit指令實現的, Monitor對象是同步的基本實現單元

Java 6之前, Monitor的實現完全是依靠操作系統內部的互斥鎖,因爲需要進行用戶態到內核態的切換,所以同步操作是一個無差別的重量級操作.

現代的(Oracle) JDK中, JVM對此進行了大刀闊斧地改進,提供了三種不同的Monitor實現,也就是常說的三種不同的鎖:

  • 偏斜鎖(Biased Locking)
  • 輕量級鎖
  • 重量級鎖

大大改進了其性能。

所謂鎖的升級、降級,就是JVM優化synchronized運行的機制,當JVM檢測到不同的競爭狀況時,會自動切換到適合的鎖實現,這種切換就是鎖的升級、降級。

沒有競爭出現時,默認會使用偏斜鎖。 JVM會利用CAS操作(compare and swap),在對象頭上的Mark Word部分設置線程ID,以表示這個對象偏向於當前線程,所以並不涉及真正的互斥鎖。這樣做的假設是基於在很多應用場景中,大部分對象生命週期中最多會被一個線程鎖定,使用偏斜鎖可以降低無競爭開銷。

如果有另外的線程試圖鎖定某個已經被偏斜過的對象, JVM就需要撤銷(revoke)偏斜鎖,並切換到輕量級鎖實現。輕量級鎖依賴CAS操作Mark Word來試圖獲取鎖,如果重試成
功,就使用普通的輕量級鎖;否則,進一步升級爲重量級鎖。

極客時間 :《Java核心技術面試精講》

自我理解

synchronized是由一對兒monitorenter/monitorexit指令實現。

不可不說的Java“鎖”事

不可不說的Java“鎖”事

流程圖:

Java中的鎖

阻塞或喚醒一個Java線程需要操作系統切換CPU狀態來完成,這種狀態轉換需要耗費處理器時間。如果同步代碼塊中的內容過於簡單,狀態轉換消耗的時間有可能比用戶代碼執行的時間還要長。

在許多場景中,同步資源的鎖定時間很短,爲了這一小段時間去切換線程,線程掛起和恢復現場的花費可能會讓系統得不償失。如果物理機器有多個處理器,能夠讓兩個或以上的線程同時並行執行,我們就可以讓後面那個請求鎖的線程不放棄CPU的執行時間,看看持有鎖的線程是否很快就會釋放鎖。

爲了讓當前線程“稍等一下”,我們需讓當前線程進行自旋,如果在自旋完成後前面鎖定同步資源的線程已經釋放了鎖,那麼當前線程就可以不必阻塞而是直接獲取同步資源,從而避免切換線程的開銷。這就是自旋鎖。

image

java對象

存放在堆內存中

對象大致可以分爲三個部分

  • 對象頭
    • Mark Word(標記字段)
    • Klass Pointer(類型指針)
  • 實例變量
  • 填充字節

Synchronized鎖對象是存在鎖對象的對象頭的MarkWord中。

鎖狀態 存儲內容 存儲內容
無鎖 對象的hashCode、對象分代年齡、是否是偏向鎖(0) 01
偏向鎖 偏向線程ID、偏向時間戳、對象分代年齡、是否是偏向鎖(1) 01
輕量級鎖 指向棧中鎖記錄的指針 00
重量級鎖 指向互斥量(重量級鎖)的指針 10

逐級遞增過程:

image

參考:
極客時間:《Java核心技術面試精講》

本筆記根據專欄主題進行學習筆記,雖然參考了許多做了筆記,但是加上了自己的整理,跟原作者的行文可能有很大偏差。如果想查看原版請自行搜索。謝謝

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