Java synchronizedキーワード実装原理
4228 ワード
使用するjavaバージョン
結論を先に言います.同期方法の場合、JVMはACC_を採用する.SYNCRONIZEDタグは同期を実現する. 同期コードブロックの場合、JVMはmonitorenter、monitorexitの2つの命令を用いて同期を実現する.
同期メソッド
MainTest.class対応バイトコードの一部コード
上のコードではtestメソッドには2つのflagがあることがわかります.
ACC_PUBLICは
同期方法の場合、JVMはACC_を採用するSYNCRONIZEDタグは同期を実現する.
メソッドレベルの同期は暗黙的です.同期メソッドにはACC_があります.SYNCRONIZEDマーク.スレッドが設定されたACCにアクセスするときSYNCRONIZEDフラグのメソッドの場合、実行スレッドはモニタを取得してからメソッドの実行を開始し、メソッドの実行後にモニタを解放する必要があります.このとき,他のスレッドが実行方法を要求すると,モニタが得られないために遮断される.メソッドの実行中に例外が発生し、メソッド内部で例外が処理されていない場合、例外がメソッドの外に投げ出される前にモニタが自動的に解放されることに注意してください.
同期コードブロック
MainTest.class対応バイトコードの一部コード
同期コードブロックの場合.JVMはmonitorenter,monitorexitの2つの命令を用いて同期を実現する.
同期コードブロックはmonitorenterとmonitorexitの2つの命令を用いて実現される.モニタrenter命令の実行をロックと理解し、モニタrexitをロック解除と理解することができる.各オブジェクトは、ロックされた回数を記録したカウンタを維持します.ロックされていないオブジェクトのカウンタは0であり、1つのスレッドがロックを取得した後、カウンタは自己増加して1になり、同じスレッドが再びオブジェクトのロックを取得したとき、カウンタは再び自己増加する.同じスレッドがロックを解放すると(monitorexit命令を実行する)、カウンタはさらに自己減算されます.カウンタが0の場合.ロックが解放され、他のスレッドがロックを取得できます.スレッドが実行するmonitorrenter命令に遭遇すると、ロックが取得されなければブロックされるロックを取得しようとします. スレッドが実行するmonitorrenter命令に遭遇すると、ロックを取得しようとします.ロックが取得されると、ロックカウント+1(なぜ1が加算されるのか、再入可能なロックなので、このロックカウントでロックの状況を判断する必要があります).モニタrexitに遭遇すると、カウンタ-1がロックされ、カウンタが0のときにロックが解除されます.
上のコードにはmonitorexitが2つあることに気づきました.
これはsynchronizedロックの解放には2つのメカニズムがあり、1つは解放を完了することである.もう1つは異常を投げ出し、仮想マシンを解放することです.図中の2番目のモニタrexitは、異常が発生した場合に実行されるフローです.また、図からは15行目にgoto命令
参照リンク: synchronizedとLockの違いと の使用について詳しく説明する Javaロック–Lock実装原理(下位実装) synchronizedとは何かと聞かれたら、この文章を彼に送ります. Javaのロックの実現原理 を理解してください. Chapter 2. The Structure of the Java Virtual Machine Chapter 6. The Java Virtual Machine Instruction Set
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)
結論を先に言います.
同期メソッド
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の場合.ロックが解放され、他のスレッドがロックを取得できます.
上のコードにはmonitorexitが2つあることに気づきました.
14: monitorexit
行目と20: monitorexit
行目.これはsynchronizedロックの解放には2つのメカニズムがあり、1つは解放を完了することである.もう1つは異常を投げ出し、仮想マシンを解放することです.図中の2番目のモニタrexitは、異常が発生した場合に実行されるフローです.また、図からは15行目にgoto命令
15: goto 23
があり、つまり正常な運転が終了すると23行にジャンプして直接戻ってくることも見られます.参照リンク: