前のブログ [Fuck Java Concurrency] - volatile の実装原理の詳細な分析で、すでに volatile の特徴が説明されています。変数書き込み;
public class VolatileTest { int i = 0; volatile boolean flag = false; //Thread A public void write(){ i = 2; //1 flag = true; //2 } //Thread B public void read(){ if(flag){ //3 System.out.println("---i = " + i); //4 } } }
操作1と操作4にhappens-beforeがある場合関係がある場合、1 は 4 に表示される必要があります。一部の学生は、「操作 1 と操作 2 の順序を入れ替えてもよいのですが、それは可能ですか?」と尋ねるかもしれません。 LZ のブログを読んでいると、volatile は可視性を確保するだけでなく、並べ替えも禁止していることがわかります。したがって、volatile 変数を書き込む前にスレッド A に表示されていたすべての共有変数は、スレッド B が同じ volatile 変数を読み取った直後にスレッド B に表示されるようになります。
JMM では、スレッド間の通信は共有メモリを使用して実装されます。 volatile のメモリ セマンティクスは次のとおりです:
volatile 変数を読み取るとき、JMM はスレッドに対応するローカル メモリを無効に設定し、共有変数をメイン メモリから直接読み取ります
それでは、揮発性メモリのセマンティクスはどのように実装されるのでしょうか?一般的な変数の場合は並べ替えられますが、揮発性変数の場合は並べ替えられません。これはメモリ セマンティクスに影響を与えるため、揮発性メモリ セマンティクスを実現するために、JMM は並べ替えを制限します。並べ替えのルールは次のとおりです。
2 番目の操作が揮発性書き込みである場合、最初の操作がどのようなものであっても、並べ替えることはできません。この操作により、揮発性書き込み前の操作がコンパイラーによって揮発性書き込みの後に並べ替えられなくなります。最初の操作が揮発性書き込みで、2 番目の操作が揮発性読み取りである場合、並べ替えることはできません。
volatile の基本的な実装はメモリ バリアを挿入することですが、コンパイラが挿入されるメモリ バリアの総数を最小限に抑える最適な配置を見つけることはほとんど不可能であるため、JMM は保守的な戦略を採用します。以下のように:
各揮発性書き込み操作の前に StoreStore バリアを挿入します
各揮発性書き込み操作の後に StoreLoad バリアを挿入します
各揮発性読み取り操作の後に LoadLoad バリアを挿入します
LoadStore バリアを挿入します各揮発性読み取り操作の後
StoreStore バリアは、揮発性書き込みの前に、その前の通常の書き込み操作がすべてメイン メモリにフラッシュされていることを保証できます。
LoadLoad バリアは、プロセッサが上の揮発性読み取りと下の通常読み取りの順序を変更するのを防ぐために使用されます。
上記の VolatileTest の例を分析してみましょう:
public class VolatileTest { int i = 0; volatile boolean flag = false; public void write(){ i = 2; flag = true; } public void read(){ if(flag){ System.out.println("---i = " + i); } } }
public class VolatileBarrierExample { int a = 0; volatile int v1 = 1; volatile int v2 = 2; void readAndWrite(){ int i = v1; //volatile读 int j = v2; //volatile读 a = i + j; //普通读 v1 = i + 1; //volatile写 v2 = j * 2; //volatile写 } }
上の図のどのメモリ バリア命令が冗長であるかを分析してみましょう
1: これは絶対に保存しておかなければなりません
2: 以下のすべての通常の書き込みは、上記の揮発性読み取りで並べ替えることが禁止されています。ただし、2 番目の揮発性読み取りが存在するため、通常の読み取りは 2 番目の揮発性読み取りをバイパスできません。したがって、省略することもできます。
3: 以下に通常の読み方はないため、省略できます。
4: 予約済み
5: 予約済み
6: その後に揮発性の記述が続くため省略可能
7: 予約済み
8: 予約済み
2、 3、6は省略可能で、概略図は以下の通りです:
上記は、[Deadly Java Concurrency] - 揮発性 Java メモリ モデルの分析の内容です。 PHP 中国語 Web サイト (m.sbmmt.com) にアクセスしてください。