Javaのメモリ・モデルは、Javaの並行処理の基礎となるサポートと言えます。Javaの並行処理を理解するには、Javaのメモリ・モデルを理解してください。
メモリモデル
メモリ上に "value = 1; "という変数を設定した場合、他のスレッドはいつその結果を読むことができますか?すぐに読まれるとは限りません。たとえば、命令の順序がソースコードの順序と異なっていたり、コンパイラが変数をメモリではなくレジスタに格納したり、プロセッサが命令を無秩序または並列的に実行したり、キャッシュが書き込まれた変数をメインメモリにコミットする順序を変更したり、プロセッサのローカルキャッシュに格納された値が他のプロセッサから見えなかったりします。
.
マルチコアプロセッサでは、各プロセッサが独自のキャッシュを持ち、メインメモリと定期的に連携しており、プロセッサアーキテクチャによって異なるレベルのキャッシュコヒーレンシが提供されています。今日のCPUでは、レジスタ、L1、L2、L3、メモリなど、複数のレベルのメモリキャッシュに分かれており、各プロセッサは独自のルールと処理方法を持っています。
メイン・メモリには主に共有変数が格納され、ワーキング・メモリは各スレッドが所有し、スレッドが必要とする共有変数のコピーが格納されます。スレッドが変数を変更するときは、まず作業メモリの変数を変更し、それをメインメモリに同期させます。
マルチスレッド環境でプログラムの直列性を維持することは、大きなパフォーマンス・オーバーヘッドをもたらします。そのため、複数のスレッドが操作を調整する必要があるのは、データを共有したいときだけで、JVMは、このような調整された操作がいつ発生するかを、同期をとることで見つけるプログラムに依存しています。2種類のメモリーだけを分割することで、よりシンプルになります。
ハプンズ・ビフォア・ルール
前節では、JVMは同期操作に依存することで協調操作が発生するタイミングを見つけ、JMMはさまざまな操作によって定義されると述べました。
Happens-beforeを簡単に説明すると、最初の操作が2番目の操作の前にHappens-beforeする場合、最初の操作が2番目の操作から見える、つまり2番目の操作が最初の操作の結果を見ることができるということです。
そして、ハプンズ・ビフォアには主に以下のルールがあります:
プロシージャの順序のルール:スレッドは、最初のステップの実行は、次のステップで実行する必要があります前に2つのステップのコードなどの実行順序を確保する必要があります、あなたがルールを保証することができない場合は、後者のステップは、前のステップの結果に依存している場合は、必ずエラーが発生します。しかし、このルールは命令の並べ替えと衝突しますが、実行の並べ替えは、並べ替えの前に実行の結果がまだハプン前の実行の結果を満たしていることを保証するためのものなので、衝突することはありません。
モニタールール:同じロックに対して、前の人がロックを解放してからでないと、後の人はロックを取得できません。
volatile 変数ルール: volatile で変更された変数があるスレッドで変更された後、他のスレッドは最新の値を見ることができなければなりません。
スレッド開始ルール:メインスレッドがサブスレッドを実行する場合、サブスレッドのrunメソッドは、メインメソッドがサブスレッドのstartメソッドを呼び出す操作を確認できなければなりません。
スレッド終了ルール:メインスレッドが子スレッドの開始を呼び出し、その後joinメソッドを呼び出す場合、joinメソッドは子スレッドのrunメソッドの実行結果を見ることができなければなりません。
Interruptルール:スレッド上でInterruptメソッドを実行した後、interruptedとisInterruptedの両方を実行して結果を確認します。
ターミネーターのルール:オブジェクトのコンストラクターは、オブジェクトのターミネーターが実行される前に完了しなければなりません。
伝達可能性:AがB上で動作し、BがC上で動作する場合、AはC上になければならず、つまりCはAの実行結果を見ることができなければなりません。
例えば、スレッドAがスレッドBのstartメソッドとスレッドBのjoinメソッドを実行する場合、スレッドBのrunメソッドはAがBのstartメソッドを呼び出した後に実行されなければなりません、つまり、Bのrunメソッドの実行結果を見ることができます。同様に、joinメソッドはrunメソッドの終了後に実行されなければなりません。
シングルトン・パターンのダブルチェック
シングルトンパターンのコードの実装の1つを以下に示します:
volatileは変数の可視性を保証します。つまり、先に述べたvolatile変数のルールは、変数シングルトンが2回目に検証されたときにのみ正しくなります。スレッドが初期化した変数がvolatileで変更されない場合、初期化の結果はメインメモリに同期されていても作業メモリに残っている可能性がありますが、他のメモリに同期されていなければ、他のスレッドが再び初期化する可能性があります。
概要
JMMは、実際に定義された一連の操作で構成され、これらの操作は、Javaの基本的な特性を決定する、特にマルチスレッド並行処理の面では、それは主にマルチスレッドの正しい実行の保証のメンテナンスのこれらの3つの側面の順序変更、原子性、メモリの可視性です。
Javaプログラマの日々の勉強ノート、誤解などの交換議論を歓迎します!