Java synchronizedキーワード実装原理

4228 ワード

使用するjavaバージョン
src git:(master) ✗ java -version 
java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)


結論を先に言います.
  • 同期方法の場合、JVMはACC_を採用する.SYNCRONIZEDタグは同期を実現する.
  • 同期コードブロックの場合、JVMはmonitorenter、monitorexitの2つの命令を用いて同期を実現する.

  • 同期メソッド
    public class MainTest {
    
        public synchronized void test() {
                System.out.println("Hello world");
        }
    
    }
    
    javap -vコマンドを使用してclass対応のバイトコードを表示します.
    javap -v MainTest
    
    

    MainTest.class対応バイトコードの一部コード
    public class com.hm.sync_test.MainTest
    
    {
    
      public synchronized void test();
        descriptor: ()V
        flags: ACC_PUBLIC, ACC_SYNCHRONIZED
        Code:
          stack=2, locals=1, args_size=1
             0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
             3: ldc           #3                  // String Hello world
             5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
             8: return
          LineNumberTable:
            line 34: 0
            line 35: 8
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       9     0  this   Lcom/hm/sync_test/MainTest;
    }
    
    

    上のコードではtestメソッドには2つのflagがあることがわかります.
     flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    

    ACC_PUBLICはaccess publicを意味し、タグ可視性はpublicである.ACC_SYNCRONIZEDはaccess synchronizedという意味で、表記はsynchronizedメソッドです.
    同期方法の場合、JVMはACC_を採用するSYNCRONIZEDタグは同期を実現する.
    メソッドレベルの同期は暗黙的です.同期メソッドにはACC_があります.SYNCRONIZEDマーク.スレッドが設定されたACCにアクセスするときSYNCRONIZEDフラグのメソッドの場合、実行スレッドはモニタを取得してからメソッドの実行を開始し、メソッドの実行後にモニタを解放する必要があります.このとき,他のスレッドが実行方法を要求すると,モニタが得られないために遮断される.メソッドの実行中に例外が発生し、メソッド内部で例外が処理されていない場合、例外がメソッドの外に投げ出される前にモニタが自動的に解放されることに注意してください.
    同期コードブロック
    public class MainTest {
    
        public void test() {
            //        
            synchronized (MainTest.class){
                System.out.println("Hello world");
            }
        }
    }
    
    

    MainTest.class対応バイトコードの一部コード
    public class com.hm.sync_test.MainTest
    
    {
    
      public void test();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=3, args_size=1
             0: ldc           #2                  // class com/hm/sync_test/MainTest
             2: dup
             3: astore_1
             4: monitorenter
             5: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
             8: ldc           #4                  // String Hello world
            10: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            13: aload_1
            14: monitorexit
            15: goto          23
            18: astore_2
            19: aload_1
            20: monitorexit
            21: aload_2
            22: athrow
            23: return
    }
    
    

    同期コードブロックの場合.JVMはmonitorenter,monitorexitの2つの命令を用いて同期を実現する.
    同期コードブロックはmonitorenterとmonitorexitの2つの命令を用いて実現される.モニタrenter命令の実行をロックと理解し、モニタrexitをロック解除と理解することができる.各オブジェクトは、ロックされた回数を記録したカウンタを維持します.ロックされていないオブジェクトのカウンタは0であり、1つのスレッドがロックを取得した後、カウンタは自己増加して1になり、同じスレッドが再びオブジェクトのロックを取得したとき、カウンタは再び自己増加する.同じスレッドがロックを解放すると(monitorexit命令を実行する)、カウンタはさらに自己減算されます.カウンタが0の場合.ロックが解放され、他のスレッドがロックを取得できます.
  • スレッドが実行するmonitorrenter命令に遭遇すると、ロックが取得されなければブロックされるロックを取得しようとします.
  • スレッドが実行するmonitorrenter命令に遭遇すると、ロックを取得しようとします.ロックが取得されると、ロックカウント+1(なぜ1が加算されるのか、再入可能なロックなので、このロックカウントでロックの状況を判断する必要があります).モニタrexitに遭遇すると、カウンタ-1がロックされ、カウンタが0のときにロックが解除されます.

  • 上のコードにはmonitorexitが2つあることに気づきました.14: monitorexit行目と20: monitorexit行目.
    これはsynchronizedロックの解放には2つのメカニズムがあり、1つは解放を完了することである.もう1つは異常を投げ出し、仮想マシンを解放することです.図中の2番目のモニタrexitは、異常が発生した場合に実行されるフローです.また、図からは15行目にgoto命令15: goto 23があり、つまり正常な運転が終了すると23行にジャンプして直接戻ってくることも見られます.
    参照リンク:
  • synchronizedとLockの違いと
  • の使用について詳しく説明する
  • Javaロック–Lock実装原理(下位実装)
  • synchronizedとは何かと聞かれたら、この文章を彼に送ります.
  • Javaのロックの実現原理
  • を理解してください.
  • Chapter 2. The Structure of the Java Virtual Machine
  • Chapter 6. The Java Virtual Machine Instruction Set