sychronized代碼塊如何保證加鎖解鎖的成對出現?

對如下這樣一個簡單的代碼用javap查看的bytecode信息

public class Demo {
		public static void main(String[] args) {
        Object lock = new Object();
        synchronized (lock) {
            System.out.println("ok");
        }
    }
}

javac -g Demo.java

javap -v Demo

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         -------- 0 ~ 7 爲 Object lock = new Object()對 應的bytecode -----
      	 //new在堆中產生新的對象的同時,將對象的一個引用放入操作數棧
         0: new           #2                  // new Object
         //dup複製一份對象的引用,是爲了用2次
         3: dup
         //執行invokespecial指令,消耗棧頂的一個對象的引用,調用構造方法
         4: invokespecial #1                  
         7: astore_1   //第二個lock引用賦給局部變量表中1號slot的name爲lock的局部變量
                  
         8: aload_1    //將對象引用加載到操作數棧
         9: dup				 //再複製一份,分別給monitorenter,monitorexit使用,分別爲加鎖和解鎖
        10: astore_2   //將剛纔新產生的對象引用 存儲到2號slot(沒有名字的slot)
        11: monitorenter   //還剩的一個對象引用被monitorenter消耗掉,這就是加鎖操作
        -------- 12 ~ 21 爲sychronized代碼塊內部-----          
        12: getstatic     #3                  // < - System.out 
        15: ldc           #4                  // < = "ok"
        17: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        20: aload_2    //將剛纔存到slot_2的對象引用加載到操作數棧給解鎖指令用
        21: monitorexit
      	22: goto          30
        //怎樣保證一定會解鎖?利用異常表
        25: astore_3   // 將異常對象的引用存到slot_3
        26: aload_2    // < - slot_2(lock引用)
        27: monitorexit  // monitorexit(lock引用),確保對同一個對象解鎖
        28: aload_3    //剛纔的異常對象引用加載進來,進行拋出
        29: athrow
        30: return
      Exception table:
         from    to  target type
            12    22    25   any
            25    28    25   any
      LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      31     0  args   [Ljava/lang/String;
          8      23     1  lock   Ljava/lang/Object;


總結:

1.sychronized用於對象上時,會產生2份對象的引用,分別給加鎖和解鎖指令用

2.sychronized用於對象上時,利用異常表,不管sychronized中的代碼是否正常執行,都將會對同一個對象解鎖

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