synchronized工作原理(一)

  • 2020 年 3 月 10 日
  • 筆記

1. synchronized同步方法

synchronized同步方法的位元組碼還原

  • java聲明的方法在jvm中的結構格式method_info
method_info {  	   u2             access_flags;  	   u2             name_index;  	   u2             descriptor_index;  	   u2             attributes_count;  	   attribute_info attributes[attributes_count];  }
  • 其中關注method_info的access_flags取值
    • ACC_SYNCHRONIZED,對應標示值為0x0020,作用是聲明為同步方法,在jvm內部包裝一個監視器鎖被調用
    • ACC_PUBLIC,對應標示值為0x0001,作用聲明方法為public,運行能被包外訪問
  • 帶synchronized的部分java代碼
// Account.java  public synchronized void setBalance(double balance) {      this.balance = balance;  }
  • 對應的java代碼的位元組碼
## 上述代碼的位元組碼如下  public synchronized void setBalance(double);  	descriptor: (D)V          flags: ACC_PUBLIC, ACC_SYNCHRONIZED  	Code:  	  stack=3, locals=3, args_size=2  		 0: aload_0  		 1: dload_1  		 2: putfield      #2                  // Field balance:D  		 5: return  	  LineNumberTable:  		line 20: 0  		line 21: 5  	  LocalVariableTable:  		Start  Length  Slot  Name   Signature  			0       6     0  this   Lcom/xiaokunliu/concurrency/sync/syncmethod/Account;  			0       6     1 balance   D   ## 從位元組碼中可以看出在方法添加synchronized關鍵字,會在編譯階段多產生一個flag,即ACC_SYNCHRONIZED

synchronized同步方法的本質

  • 摘錄jvm規範中的原文
1) Method-level synchronization is performed implicitly, as part of method invocation and return.  2) A synchronized method is distinguished in the run-time constant pool's method_info structure by the ACC_SYNCHRONIZED flag, which is checked by the method invocation instructions.  3) When invoking a method for which ACC_SYNCHRONIZED is set, the executing thread enters a monitor, invokes the method itself, and exits the monitor whether the method invocation completes normally or abruptly.  4) During the time the executing thread owns the monitor, no other thread may enter it. If an exception is thrown during invocation of the synchronized method and the synchronized method does not handle the exception, the monitor for the method is automatically exited before the exception is rethrown out of the synchronized method  
  • 簡言概括
1) 方法級同步在JVM中是隱式執行的,是作為方法調用和返回的一部分  2) 同步方法在運行時常量池的method_info結構中由ACC_SYNCHRONIZED標誌加以區分,該標誌由方法調用指令進行檢查  3) 執行線程識別到方法中含有ACC_SYNCHRONIZED標誌將會獲取一個監視器對象然後調用方法,最後而且不論當線程正常執行或是異常退出時將會釋放監視器對象  4) 在執行期間,執行線程持有監視器對象,而其他執行線程將無法獲取監視器對象,如果方法拋處異常將會釋放監視器對象
2. synchronized同步代碼塊

synchronized同步代碼塊位元組碼還原

  • java同步代碼塊
System.out.println(Thread.currentThread().getName() + " get controlCinema1 lock, add number is " + number);
  • 同步代碼塊對應的位元組碼
53: monitorexit
  • 位元組碼解讀
    • jvm通過monitorenter來完成加鎖的操作
    • 53行的monitorexit之後是go語句到62行,屬於程序正常退出釋放鎖的操作
    • 59行的monitorexit之後是athrow的位元組碼指令,表示當程序異常的時候釋放鎖的操作
    • monitorenter和monitorexit支持編譯指令來實現同步指令

synchronized同步代碼塊的工作原理

  • 引入jvm規範原語
1) Synchronization of sequences of instructions is typically used to encode the synchronized block of the Java programming language.  2) The Java Virtual Machine supplies the monitorenter and monitorexit instructions to support such language constructs.  3) Proper implementation of synchronized blocks requires cooperation from a compiler targeting the Java Virtual Machine
  • 簡言概括之
1) 指令序列的同步通常用於java程序中的同步代碼塊  2) jvm支持在編譯階段執行同步指令  3) 同步塊的實現需要java編譯器的支持
3. synchronized工作原理小結

結構化鎖

結構化鎖定是這樣一種情況:在方法調用期間,給定監控器上的每個出口與該監控器上的前一個入口匹配。  由於不能保證提交給Java虛擬機的所有代碼都將執行結構化鎖定,所以允許Java虛擬機的實現
  • jvm通過以下規則保證結構化鎖定:
    • 不論方法是正常還是異常退出,jvm必須保證線程對監視器入口(monitorenter)的執行次數與對監視器出口(monitorexit)的執行次數相等
    • 在方法調用期間,線程對監視器執行的出口次數(monitorexit)不可能超過對監視器入口的執行次數(monitorenter)

工作原理本質

  • synchronized的實現是通過jvm的監視器的入口和出口來實現的
  • synchronized同步方法是隱式實現(編譯階段僅看到同步標誌)
  • synchronized同步代碼塊是顯示實現(編譯階段可見)

注意點

  • jvm通過一個單一的同步結構:監視器來支持方法和方法中的指令序列的同步
  • 使用synchronized同步代碼塊不論程序是正常完成還是異常退出都會自動釋放鎖