2

Java 同時実行チュートリアルには、次のように記載されています。

読み取りと書き込みは、参照変数とほとんどのプリミティブ変数 (long と double を除くすべての型) に対してアトミックです。
読み取りと書き込みは、volatile と宣言されたすべての変数 (long 変数と double 変数を含む) に対してアトミックです。

これをテストするための簡単な実験を作成しました

package experiment0;

public class Experiment0 {

    public static int i=9;

    public static void main(String[] args) {
        i=9;
        (new Thread(){
            public void run(){
                while(i==9){
                    //System.out.println("i==9");
                }
                System.out.println("\ni!=9");
            }
        }).start();
        (new Thread(){
            public void run(){
                try{
                    Thread.sleep(3000);
                    i=8;
                }catch(Exception e){

                }
            }
        }).start();
    }
}

このコードを実行すると、プログラムが終了することはありません! それが機能するためには、最初のスレッドの while ループ内の行のコメントを解除するか、iとして宣言する必要がありvolatileます。何か不足していますか?この種のケースでは、すべてのプリミティブを揮発性として宣言する必要があると言うべきですか? System.out問題を「解決」するために書き込みを行うのはなぜですか? 2番目のスレッドが変更されるのに十分な時間を与えますiか?

4

1 に答える 1

3

アトミックな書き込みとは、書き込みが単一のアトミック操作として実行されることを意味します。他のスレッドは、割り当て前または割り当て後の値以外のものを見ることができませんでした。

たとえば、長い値の場合、割り当ては実際には 2 つの操作として実行されるため、アトミックではありません。1 つは最初の 32 ビットを割り当て、もう 1 つは最後の 32 ビットを割り当てます。そのため、2 つの操作のうちの 1 つだけが実行された後に、別のスレッドが変数の値を読み取る可能性があります。したがって、前の値でも後の値でもなく、「中間」の値である値が表示されます。

あなたのプログラムが示しているのは、同期を行わずに変数に書き込むと、スレッド間の可視性の問題が発生することです。あるスレッドによって行われた書き込みは、別のスレッドからは見えません。これは、プロセッサがそれぞれ独自のキャッシュを持ち、割り当てごとにメイン メモリに書き込まないためです。書き込みが確実に見えるようにするには、変数を揮発性にするか、変数へのアクセスを同期するか、AtomicInteger を使用する必要があります。

于 2012-10-21T14:22:48.667 に答える