ホームページ  >  記事  >  Java  >  Java同期とは

Java同期とは

WBOY
WBOY転載
2023-05-14 08:28:051712ブラウズ

Synchronized とは

Java 読者の皆さん、あなたは synchronized キーワードに馴染みがあるでしょう。これはさまざまなミドルウェア ソース コードや JDK ソース コードで見られます。synchronized に詳しくない読者にとっては、 synchronized によってスレッドの安全性が確保されることを理解して、synchronized キーワードを使用する必要があります。

  • 呼び出し先: ミューテックス ロック (同時に実行できるのは 1 つのスレッドのみで、他のスレッドは待機します)

  • 別名: 悲観的ロック (同時に実行できるのは 1 つのスレッドだけであり、他のスレッドは待機します)

  • JVM 仮想マシンが実装に役立ちます。開発者は synchronized キーワードを使用するだけで済みます。

  • これを使用する場合は、オブジェクトをロック ミューテックスとして使用する必要があります。

  • コードの原子性と可視性を確保できます。 (クリティカルセクション)。

Synchronized キーワードをバイトコード レベルから分析する

ケースから始めるのが最も適切です。

class Demo1{
    // 互斥对象
    static Object object = new Object();
    // 竞争条件
    static int cout = 0;
    public static void main(String[] args) {
        // 互斥
        synchronized(object){
            // 以下是临界区
            cout++;
            System.out.println("synchronized");
        }
    }
}

Java コードだけからは何もわかりません。Java プログラムはバイトコード ファイルにコンパイルされるため、バイトコードを解析します

定数プール:
#1 = Methodref #7.#26 // java/lang/Object."5655bee0e910362c4b50f45afb3465e0
#14 = Utf8 ()V
#15 = Utf8コード
#16 = Utf8 LineNumberTable
#17 = Utf8 main
#18 = Utf8 ([Ljava/lang/String;)V
#19 = Utf8 StackMapTable
#20 = クラス#36 // " [Ljava/lang/String;"
#21 = クラス #34 // java/lang/Object
#22 = クラス #37 // java/lang/Throwable
#23 = Utf8 ;
#24 = Utf8 SourceFile
#25 = Utf8 Demo1.java
#26 = NameAndType #13:#14 // "7e51f00a783d7eb8f68358439dee7daf":()V
#27 = NameAndType #9:#10 // object:Ljava/lang/Object;
#28 = NameAndType #11:#12 // cout:I
#29 = クラス #38 // java/lang/System## ##30 = nameandtype#39:#40 // out:ljava/io/printstream;
#31 = utf8同期
#32 =クラス#41 // java/io/printStream
# 33 = NameAndType #42:#43 // println:(Ljava/lang/String;)V
#34 = Utf8 java/lang/Object
#35 = Utf8 Demo1
#36 = Utf8 [Ljava/lang /String;
#37 = Utf8 java/lang/Throwable
#38 = Utf8 java/lang/System
#39 = Utf8 out
#40 = Utf8 Ljava/io/PrintStream;
#41 = Utf8 java/io/PrintStream
#42 = Utf8 println
#43 = Utf8 (Ljava/lang/String;)V
0: getstatic #2 //从2号常量池中拿到静态变量,压入操作数栈中
3: dup // 操作数栈顶の对象赋值一份
4: ASTORE_1 // 運用番号スタックのデータをローカル変数テーブル No. 1 に保存し、
を使用します。 5: Monitorenter // 解放ロックでロックを開き、同期化されたバイトコード層でもあります。 implement
6: getstatic #3 // 定数プールNo.2からstatic変数を取得し、オペランドスタックにプッシュ
9: iconst_1 iconst_1 // 定数1をオペランドスタックにプッシュ
10: iadd 10: iadd // 消費 2つのオペランドスタックのデータを加算してスタックの先頭にプッシュします
11: putstatic #3 // オペランドスタックの先頭の変数を定数プールNo.に代入します。 3
14: getstatic #4 // 定数プール4番のオブジェクトをオペランドスタックにプッシュ
17: ldc #5 // 定数プール5のシンボルを解析し、文字列定数「synchronized」を取得
19: invokevirtual #6 // println関数実行、演算スタック2個消費
22: ALOAD_1 // ローカル変数テーブル1のデータを演算番号スタックに押し込む
23: Monitorexit // 終了相互ロックの同期実装のバイト コード レベルでもあります。
24: goto 32 // 32 行目にジャンプします。
27:Monitorexit命令で使用されるスタックの上部からAstore_2
29:Monitorexit //例外があるかもしれませんが、ロックをリリースする必要があります。
30: aload_2 ‐ 32 にスローされる例外を受け取るには、 // Function returns


上記はバイトコードの完全な説明です。実際には非常に簡単です。最後に、同期キーワードは、monitorenter およびmonitorexit バイトコード命令に解析され、これら 2 つのバイトコード命令を実行するたびに、mutex オブジェクトが、monitorenter およびmonitorexit バイトコード命令で使用できるようにオペランド スタックにプッシュされます。

したがって、次の記事では、Hotspot ソース コードに移動して、monitorenter およびmonitorexit バイトコード命令の詳細なプロセスを解析します。

Synchronized ロックと ReentrantLock の違い

これは非常に一般的な面接の質問であり、面接でも非常に頻繁に尋ねられます

類似点:

両方はミューテックス ロックの実装です。

違い:

Synchronized は JVM の内部実装に基づいており、ReentrantLock は Java レベルで実装されます (ただし、コアReentrantLock のコードは引き続き C コードを呼び出します)。
  • Synchronized は 1.6 以降で最適化されています。ロックにはいくつかの異なるレベルがあり、スレッドの競合の激しさに応じてロックの強度が増加します (一般にロック アップグレードと呼ばれます)。はシナリオにより適していますが、ReentrantLock はロック強度の選択が少し厳密です。
  • ReentrantLock はロック強度の選択が若干厳格ですが、公平なロックと不公平なロックのどちらかを選択できますが、Synchronized は不公平なロックのみを選択できます
  • ReentrantLock の条件付き待機キューは、高度にカスタマイズされた複数のキューを作成できます。 Synchronized の最後にはキューが 1 つだけあります。
  • ReentrantLock では、ユーザーが手動でロックを開いて手動でロックを解放する必要があります。 Synchronized キーワードの最下層は、バイトコード
  • によって自動的に実装されます。

以上がJava同期とはの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。