java中synchronized關鍵字的實現

說明:java

java中的同步(synchronized)是基於進入monitor對象和退出monitor對象來實現的,不管是顯式同步仍是隱式同步。

synchronized語句塊:線程

1)(使用javap -c 類名)將class文件反編譯後能夠看到:同步塊的入口位置和出口位置(方法結束處和異常處)分別插入了monitorenter字節碼指令和monitorexit字節碼指令,故同步代碼塊屬於顯示同步。
2)線程執行到monitorenter指令時,嘗試獲取對象的鎖。

synchronized方法:code

1)JVM從Class文件中的方法結構(method_info)中的 ACC_SYNCHRONIZED 訪問標誌區分一個方法是否爲同步方法,故同步方法屬於隱式同步。
2)當方法調用時,調用指令會檢查方法的ACC_SYNCHRONIZED訪問標誌是否被設置,若是設置了,執行線程將先持有monitor,而後再執行方法,最後在方法完成時釋放monitor。
3)在方法執行期間,其它線程沒法獲取該monitor。
4)若是一個同步方法執行期間拋出了異常,而且在方法內部沒法處理此異常,那這個同步方法所持有的monitor將在異常拋到同步方法以外時自動釋放。

method_info 結構格式以下(java虛擬機規範中的摘錄):
	method_info {
		u2 access_flags;	// 用於定義當前方法的訪問權限和基本屬性的標誌
		u2 name_index;
		u2 descriptor_index;
		u2 attributes_count;
		attribute_info attributes[attributes_count];
	}
	method_info結構中訪問標記(access_flags)的取值:
		標記名				值		說明
		ACC_PUBLIC			0x0001	public,方法能夠從包外訪問
		ACC_PRIVATE			0x0002  private,方法只能本類中訪問
		ACC_PROTECTED		0x0004  protected,方法在自身和子類能夠訪問
		ACC_STATIC			0x0008  static,靜態方法
		ACC_FINAL			0x0010  final,方法不能被重寫
		ACC_SYNCHRONIZED	0x0020  synchronized,方法由monitor同步
		...

獲取鎖和釋放鎖的內存原語:

	當線程獲取鎖時,JMM會把該線程對應的本地內存置爲無效。從而使得被monitor保護的臨界區代碼必須從主內存中讀取共享變量。
	當線程釋放鎖時,JMM會把該線程對應的本地內存中的共享變量刷新到主內存中
	即:
		1將本地內存中的數據設置爲無效,
		2從主內存中將數據複製到本地內存中,
		3在本地內存中進行操做,
		4操做完成後將本地內存中的數據刷新到主內存中。總體看起來就像是直接在主內存中操做同樣。

synchronized的可重入性:

1)當一個線程再次請求本身持有對象鎖的臨界資源時,這種狀況屬於重入鎖,請求將會成功。
2)因爲synchronized是基於monitor實現的,故每次重入,monitor中的計數器仍會加1。
相關文章
相關標籤/搜索