Java提供了多種機制實作多執行緒之間有需要同步執行的場景需求,其中最基本的是Synchronized ,實作上使用物件監視器( Monitor ),
Java中的每個物件都是與執行緒可以鎖定或解鎖的物件監視器( Monitor )關聯,在同一時間只有一個執行緒可以在物件監視器( Monitor )上保持鎖定,任何其他執行緒試圖鎖定物件監視器( Monitor )都會被阻止,直到它們可以獲得該監視器上的鎖定,
Synchronized 基本使用方式
Synchronized 的作用范圍,依據鎖定的物件(object、this、class)、使用方式,可以分成五種情況,如果按照JVM位元組碼的區別,也可以分成兩種形式:代碼塊(monitorenter、monitorexit)、函式(ACC_SYNCHRONIZED),
雖然可以按照不同維度來劃分 Synchronized 但本身機制是一樣的,無論是 Synchronized 函式/代碼塊,都是通過物件監視器( Monitor )來實作,無論是this、class、object本質上都是一個物件,區別無非代表的是當前實體、類、一般實體,它們都有著物件監視器( Monitor ),
在HotSpot虛擬機中,物件監視器( Monitor ) 具體的實作類就是 ObjectMonitor(C++),
在使用/分析 Synchronized 同步是否有效正確的時候,只需要分析需要的同步塊是否作用在同一個物件監視器( Monitor )上,換一種描述,是否作用在同一個物件(Object)上,這里(Object)可以是this、object、class,

下面分別按照Synchronized 代碼塊、Synchronized 函式維度來進行詳細介紹,
Synchronized 代碼塊
Synchronized 代碼塊的一般使用形式:synchronized ( Expression ) Block ,
Expression 必須是一個物件,可以是class、this、object,不能是原始型別(int、float...);否則編譯的時候就會報錯,如果 Expression 是null,會拋出NullPointerException 的例外,
Block表示一段邏輯代碼,執行邏輯代碼前會鎖定Expression 的物件監視器( Monitor ),如果正常運行完成后,物件監視器( Monitor )會被釋放;如果運行期間例外/中斷了同樣的也會釋放物件監視器( Monitor ),先加鎖確保其他執行緒無法進入執行,所以Synchronized 是悲觀鎖,JVM指令上使用monitorenter、monitorexit 來進行相關實作,

在位元組碼指令里可以也可以看到有兩個monitorexit ,一個是正常運行后的釋放;另一個是在例外(athrow)拋出前的釋放,同一個執行緒可以多次進入被鎖定的相同物件監視器( Monitor ),所以Synchronized 是可重入鎖,

Synchronized 函式
Synchronized函式在同步原理上同 Synchronized代碼塊是沒有區別的,都是通過鎖定物件監視器( Monitor );區別在于這里的物件是隱藏了起來,同樣的支持可重入,
如果是靜態方法(static),鎖定的物件是這個方法所在的class object 物件,
如果是普通的方法,鎖定的是this(當前實體)物件,
編譯成JVM位元組碼的時候,函式描述上會標識ACC_SYNCHRONIZED ,并不會在函式代碼塊中顯示的使用monitorenter、monitorexit指令,
在呼叫函式前鎖定物件監視器( Monitor ),完成運行后釋放物件監視器( Monitor ),無論函式是否有顯性的拋出/處理例外,如果有例外中斷拋出前也會自動的釋放鎖定的物件監視器( Monitor ),

Synchronized 實作原理
Synchronized同步一直也在進行優化,也是跟隨著JDK新理念一起發展,比如偏向鎖、輕量鎖、重量鎖、適應性自旋等等機制,不同的JDK版本,不同的JVM可能都有所不同,
在HotSpot虛擬機中,拋開鎖升級、自適應等機制;基本原理是執行緒通過 CAS搶占物件監視器( Monitor ) _Owner來實作鎖,沒有搶占的會進入 _EntryList 來進行放置,當然, 執行緒執行/中斷釋放_Owner后,_EntryList并不是簡單按照FIFO來進行選擇執行不會保證公平性,所以Synchronized是非公平鎖,

圖中_WaitSet沒有體現用途,但其是很重要的一個結構, 用于當 _Owner 執行執行緒中斷時,執行緒將會寫入,值得注意獲取到鎖之后才能中斷,等待鎖時不可中斷,當相關執行緒被喚醒后,會采有不同的策略重新回到_EntryList 或者 參與CAS競爭 _Owner,這里存在執行緒背景關系切換的可能,
詳細可以查看相關原始碼:
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/69087d08d473/src
在最后綜述下Synchronized 特性:悲觀鎖、可重入鎖、非公平鎖,
歡迎長期關注公眾號/頭條號(Java研究者)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/519228.html
標籤:Java
