2

私はJCIPの例を試していましたが、以下のプログラムは機能しないはずですが、20回実行しても常に機能し、この場合でも表示されるようになっていreadyますnumber

public class NoVisibility {
private static boolean ready;
private static int number;

private static class ReaderThread implements Runnable {
    public void run() {
        while (!ready)
            Thread.yield();
        System.out.println(number);
    }
}

public static void main(String[] args) {
    System.out.println(Runtime.getRuntime().availableProcessors());
    //Number of Processor is 4 so 4+1 threads
    new Thread(new ReaderThread()).start();
    new Thread(new ReaderThread()).start();
    new Thread(new ReaderThread()).start();
    new Thread(new ReaderThread()).start();
    new Thread(new ReaderThread()).start();

    number = 42;
    ready = true;
}
}

私のマシンでは、常に印刷されます

4 -- Number of Processors
42
42
42
42
42

According to Listing 3.1 of JCIP It should sometimes print 0 or should never terminate it also suggest that there is no gaurantee that ready and number written by main thread will be visible to reader thread

更新 すべてのスレッドで同じ出力を実行した後、メイン スレッドに 1000 ミリ秒のスリープを追加しました。私はプログラムが壊れていることを知っており、そのように動作することを期待しています

4

2 に答える 2

3

このプログラムは壊れているためreadynumberとして宣言する必要がありますvolatile。およびはプリミティブ変数であるため、それらに対する操作はアトミック
です、他のスレッドから見えることは保証されません。 スケジューラがスレッドを後で実行しているように見えるため、とが初期化されていることがわかります。しかし、それは 1 つのスケジュールにすぎません。 たとえば、スケジューラに影響を与えるために a を追加すると、異なる結果が表示されます。 したがって、本が正しいかどうかは保証されません。readynumber
mainnumberready
sleepmain
Runnable変数はvolatile.

更新:ここでの問題は、コンパイラが
不足しているため、フィールドを 1 回だけ自由に読み取り、ループの実行ごとにキャッシュされた値を再利用できることです。 プログラムには本質的な欠陥があります。また、スレッドの問題により、通常、アプリケーションをフィールドにデプロイするときに問題が発生します.... JSLから: volatileready

たとえば、次の (壊れた) コード フラグメントでは、 this.done が非揮発性ブール フィールドであると想定しています。

while (!this.done)
Thread.sleep(1000);

コンパイラは、フィールド this.done を 1 回だけ自由に読み取り、ループの各実行でキャッシュされた値を再利用できます。これは、他のスレッドが this.done の値を変更したとしても、ループが終了しないことを意味します。

于 2012-09-09T17:28:40.243 に答える
1

心に留めておくべき重要なことは、壊れた並行プログラムは、JVM のオプション、マシン アーキテクチャなどの適切な組み合わせで常に動作する可能性があるということです。別のコンテキストでは失敗する可能性があるため、それは良いプログラムにはなりません。同時実行の問題が表示されないということは、何もないという意味ではありません。

つまり、並行プログラムが正しいことをテストで証明することはできません。

あなたの特定の例に戻ると、あなたが説明したのと同じ動作が見られます。しかし、while ループ内の命令を削除するとThread.yield()、8 つのスレッドのうち 3 つが停止して 42 を出力しますが、残りは停止せず、プログラムは決して終了しません。

于 2012-09-09T20:10:53.830 に答える