一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して11日目です。クリックしてイベント詳細をご覧ください。
同期の使用方法
Javaのすべてのオブジェクトはロックとして機能でき、次の3つの形式で表すことができます。
- 通常のメソッドを変更します。ロックは現在のインスタンスオブジェクトです。
- 静的同期メソッドを装飾します。ロックは現在のクラスのClassオブジェクトです。
- コードブロックを変更します。ロックは同期された角かっこで構成されたオブジェクトです。
これらのロック方法を例で見てみましょう
同期方式
public synchronized void addI
同期メソッドはロックされています。コマンドを使用してjavap-c-v FileName.classファイルをバイトコード命令に変換した後、
主な結果は次のとおりです。
public void addII(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=3, locals=3, args_size=2
.... 省略
public synchronized void addI(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC, java
Code:
stack=3, locals=3, args_size=2
复制代码
同期メソッドブロックにフラグACC_SYNCHRONIZEDがあり、このメソッドが同期されていることを示していることがわかります。非同期メソッドフラグには、ACC_SYNCHRONIZEDフラグはありません。
静的メソッドの同期
public class InternalVariable {
public static void addIII(String username){
// ... 代码省略
}
}
复制代码
逆コンパイルしてコアコンパイル結果を表示します。
public static synchronized void addIII(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
Code:
stack=3, locals=3, args_size=1
复制代码
通常のメソッドと比較して、静的メソッドにはフラグフラグにもう1つのACC_STATICがあります。
同期されたコードブロック
public class InternalVariable {
public void addIIII(String username) {
synchronized (this) {
// ... 代码
}
}
}
复制代码
逆コンパイルの結果は次のとおりです。
public void addIIII(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=3, locals=6, args_size=2
0: aload_0
1: dup
2: astore_2
3: monitorenter
// ... 省略
135: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
138: aload_2
139: monitorexit
140: goto 150
143: astore 5
145: aload_2
146: monitorexit
147: aload 5
149: athrow
150: return
复制代码
同期コードブロックにはmonitorenterが1つあり、monitorexitは2つあります。これは、JVMが例外ハンドラーを自動的に生成して、例外が発生したときにメソッドがロックを正常に解放できるようにするためです。目的は、monitorexit命令を実行することです。
同期された基盤となる実装
同期の基本的な実装はJVMによって異なります。JVMでの同期の実装は、monitor lock monitorenterおよびmonitorexit命令を介して、または暗黙的にメソッド呼び出し(同期フラグの検出)およびreturn命令を介して実装されます。前者は同期コードブロックに対応し、後者は同期方式である静的同期方式に対応します。
したがって、同期メソッドは最終的にモニターロックを介してスレッドの同期を完了します。これは、モニターの入口と出口を介したJVMの同期に違反しません。