4

この単純なコードがあります。

class A {
    static volatile String[] a = new String[9];

    public static void main(String[] args) {
        new Thread() {
            public void run() {
                for (int i = 0; i < a.length; i++) {
                    while (a[i] == null);
                    System.out.println(a[i]);
                }
            }
        }.start();

        a[0] = "The";
        zzz();
        a[1] = "quick";
        zzz();
        a[2] = "brown​";
        zzz();
        a[3] = "fox";
        zzz();
        a[4] = "jumped";
        zzz();
        a[5] = "over";
        zzz();
        a[6] = "the";
        zzz();
        a[7] = "lazy";
        zzz();
        a[8] = "cat";
        zzz();
    }

    public static void zzz() {
        try {
            Thread.sleep(300);
        } catch (Exception e) {}
        a=a;
    }
}

それは私が期待するものを出力します:

$ javac A.java && java A
The
quick
brown​
fox
jumped
over
the
lazy
cat

奇妙なのはa=ainzzz()です。外しても特に変化はないようです。なぜそこにあるのですか?

4

1 に答える 1

4

私が考えることができる唯一の理由は、そのコードを書いた人が、配列のみが揮発性であり、その内容ではなくa = a、配列項目に対して実行された書き込みの可視性を強化するために追加されたことを理解していたということです。

外しても特に変化はないようです。

JVM を搭載したマシンで引き続き機能するという事実は、別の JVM を搭載した別のマシンでも機能するという意味ではありません。理論的には、ステートメントを削除すると、a = a;終わりのない while ループが発生する可能性があります。


サイドノート

Java メモリ モデル (JMM) を使用すると、a を無視できるのと同じように、JVM がそのステートメントを無視できると考えていたでしょうsynchronized(new Object())

ただし、そうではないようです*

上記の volatile 書き込みを配列だけで取得する方法を提供したことに気付いたかもしれません:自己参照を書き出すことです。

*Jeremy Manson は JMM の著者の 1 人です。

于 2013-06-26T18:08:32.233 に答える