深度解析:Synchronized原理

  說起synchronized的原理吧,必須要從jvm的內存結構說起。每一個對象在被創建出來的時候都會在堆中爲其分配內存空間,每一個對象含有三個部分組成:對象頭、實例數據、對齊填充,其中對象頭又分爲三部分:自身運行時數據、類型指針、數組長度(如果是一個數組對象的話)。其中自身運行時數據又被稱爲Mark Word,這個Mark Word中含有很多信息,例如:對象的哈希碼,對象的分代年齡,GC標識,鎖標誌位,偏向線程ID等等。其中的重量級鎖指針指向一個Monitor對象,它是依賴MonitorObject來實現的,每一個對象在創建的時候都會爲期分配一個Monitor對象,而這個MonitorObject是由C++編寫的。

  好了,有了這些底層知識,切入主題。在java的字節碼文件中有兩個指令:monitorenter和monitorexit,根據虛擬機規範的要求,在執行monitorenter指令的時候,首先要嘗試獲取對象鎖也就是這個Monitor對象,如果當前對象沒有被鎖定,或者當前線程已經獲取的該對象的鎖,那麼就會將鎖的計數器加一。反之,在執行monitorexit指令的時候就將鎖的計數器減一,如果獲取對象所失敗就會將其放進Monotor對象的_WaitSet隊列當中,直到鎖被釋放爲止。

  但值得注意的是,我們會發現在java字節碼當中會出現不止一個monitorexit指令,可能一個monitorenter指令對應兩個monitorexit指令。這是因爲java虛擬機爲了保證在方法出現異常的情況下也能保證monitorenter和monitorexit指令正常配對執行,虛擬機會自動生成一個異常時的monitorexit指令,保證在方法出現異常的時候Monitor對象也能正常被釋放。

  以上說的是synchronized同步代碼塊的原理,但是同步方法並不是採用monitorenter指令和monitorexit指令,而是採用的ACC_SYNCHRONIZED標識,當字節碼讀取器執行到此的時候就知道下面的方法是一個同步方法了。

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