ホームページ >Java >&#&チュートリアル >[Java 同時実行性との戦い]-----Java メモリ モデルの揮発性の分析

[Java 同時実行性との戦い]-----Java メモリ モデルの揮発性の分析

黄舟
黄舟オリジナル
2017-02-24 10:07:471484ブラウズ

前のブログ [Fuck Java Concurrency] - volatile の実装原理の詳細な分析で、すでに volatile の特徴が説明されています。変数書き込み;

  1. volatile アトミック; i++ などの複合操作を除き、volatile は「メモリ バリア」を使用します。 volatile セマンティクスを実装する

  2. 次に、LZ は、happens before 原則と volatile メモリ セマンティクスを通じて volatile を導入します。

    揮発性とハプエンドビフォア
  3. このブログ [Deadly Java Concurrency] - Java Memory Model Happend-Before で、LZ は、happend-before がデータ競合があるかどうか、およびスレッドが安全かどうかを判断するための主な基礎であると説明しています。マルチスレッド環境での可視性を確保します。古典的な例を使用して、揮発性変数の読み取りと書き込みによって確立される前に発生する関係を分析してみましょう。

    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
            }
        }
    }

    happens-before の原則によれば、上記のプログラムでは次の関係が得られます。
  4. happens-before原則の揮発性によると: 2 happens-before 3;

happens-beforeの推移性によると: 1 happens-before 4

操作1と操作4にhappens-beforeがある場合関係がある場合、1 は 4 に表示される必要があります。一部の学生は、「操作 1 と操作 2 の順序を入れ替えてもよいのですが、それは可能ですか?」と尋ねるかもしれません。 LZ のブログを読んでいると、volatile は可視性を確保するだけでなく、並べ替えも禁止していることがわかります。したがって、volatile 変数を書き込む前にスレッド A に表示されていたすべての共有変数は、スレッド B が同じ volatile 変数を読み取った直後にスレッド B に表示されるようになります。

    volatile のメモリ セマンティクスとその実装
  • JMM では、スレッド間の通信は共有メモリを使用して実装されます。 volatile のメモリ セマンティクスは次のとおりです:

  • volatile 変数を書き込むと、JMM はスレッドに対応するローカル メモリ内の共有変数値をメイン メモリに即座にリフレッシュします。

    volatile 変数を読み取るとき、JMM はスレッドに対応するローカル メモリを無効に設定し、共有変数をメイン メモリから直接読み取ります

  • そのため、volatile の書き込みメモリ セマンティクスはメイン メモリに直接更新され、メモリ セマンティクスは読み取り値はメインメモリから直接読み取られます。

    それでは、揮発性メモリのセマンティクスはどのように実装されるのでしょうか?一般的な変数の場合は並べ替えられますが、揮発性変数の場合は並べ替えられません。これはメモリ セマンティクスに影響を与えるため、揮発性メモリ セマンティクスを実現するために、JMM は並べ替えを制限します。並べ替えのルールは次のとおりです。

  • 翻訳は次のとおりです。

最初の操作が揮発性読み取りの場合、2 番目の操作がどのようなものであっても、並べ替えることはできません。この操作により、揮発性読み取り後の操作がコンパイラーによって揮発性読み取りの前に並べ替えられなくなります。

2 番目の操作が揮発性書き込みである場合、最初の操作がどのようなものであっても、並べ替えることはできません。この操作により、揮発性書き込み前の操作がコンパイラーによって揮発性書き込みの後に並べ替えられなくなります。


最初の操作が揮発性書き込みで、2 番目の操作が揮発性読み取りである場合、並べ替えることはできません。


volatile の基本的な実装はメモリ バリアを挿入することですが、コンパイラが挿入されるメモリ バリアの総数を最小限に抑える最適な配置を見つけることはほとんど不可能であるため、JMM は保守的な戦略を採用します。以下のように:

  1. 各揮発性書き込み操作の前に StoreStore バリアを挿入します

  2. 各揮発性書き込み操作の後に StoreLoad バリアを挿入します

  3. 各揮発性読み取り操作の後に LoadLoad バリアを挿入します

LoadStore バリアを挿入します各揮発性読み取り操作の後

  • StoreStore バリアは、揮発性書き込みの前に、その前の通常の書き込み操作がすべてメイン メモリにフラッシュされていることを保証できます。

  • StoreLoad バリアの機能は、後続の揮発性読み取り/書き込み操作によって揮発性書き込みが並べ替えられるのを防ぐことです。
  • LoadLoad バリアは、プロセッサが上の揮発性読み取りと下の通常読み取りの順序を変更するのを防ぐために使用されます。

  • LoadStore バリアは、プロセッサが揮発性読み取りを上に、通常の書き込みを下に並べ替えることを防ぐために使用されます。
  • 上記の 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); 
            }
        }
    }
  • volatile 命令のメモリ バリアの凡例を、例を通して少し示します。実際、Volatile のメモリ バリア挿入戦略は非常に保守的であり、揮発性の書き込み/読み取りメモリのセマンティクスが変更されない限り、コンパイラは特定の状況に応じて最適化し、不要なバリアを省略できます。以下は (Fang Tengfei の「The Art of Java Concurrent Programming」から抜粋):
  • 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は省略可能で、概略図は以下の通りです:

[Java 同時実行性との戦い]-----Java メモリ モデルの揮発性の分析


上記は、[Deadly Java Concurrency] - 揮発性 Java メモリ モデルの分析の内容です。 PHP 中国語 Web サイト (www.php.cn) にアクセスしてください。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。