12

この質問は、メモリの可視性のみに関連しており、発生前および発生後ではありません。Java には、あるスレッドのメモリへの変更が別のスレッドから見えるようにすることを保証する 4 つの方法があります。(参照http://gee.cs.oswego.edu/dl/cpj/jmm.html )

  1. 書き込みスレッドが同期ロックを解放し、その後、読み取りスレッドが同じ同期ロックを取得します。
  2. フィールドが volatile として宣言されている場合、書き込みスレッドがさらにメモリ操作を実行する前に、そのフィールドに書き込まれた値はすべてフラッシュされ、書き込みスレッドによって可視になります (つまり、当面の目的のためにすぐにフラッシュされます)。
  3. スレッドがオブジェクトのフィールドに初めてアクセスすると、フィールドの初期値か、他のスレッドによって書き込まれた後の値が表示されます。
  4. スレッドが終了すると、書き込まれたすべての変数がメイン メモリにフラッシュされます。

Java Concurrency in Practice によると、そのような質問に関する聖書:

volatile 変数の可視性効果は、volatile 変数自体の値を超えて拡張されます。スレッドAが揮発性変数に書き込み、続いてスレッドBが同じ変数を読み取ると、揮発性変数に書き込む前にAに表示されていたすべての変数の値は、揮発性変数を読み取った後にBに表示されます。

揮発性の質問

これは、 AからCではなく A から B にメモリフラッシュする方法を知るために、JVM が実際に volatile 変数の読み取りと書き込みを追跡することを意味しますか? したがって、 Aが変数に書き込み、後でCが変数から読み取り、その後Bが変数から読み取り、フラッシュはABおよびACの間でスレッドごとに行われますが、BCは行われませんか? または、スレッドに関係なく、キャッシュされたすべてのメモリがフラッシュされることを意味しますか? volatile 変数のみがフラッシュされますか、それともキャッシュされたメモリはすべてフラッシュされますか?

同期質問

キーワード flushing の場合synchronized、ロック内で更新されたメモリのみが他のスレッドに公開されることが保証されます。これは、次のコードで を実行している 2 つのスレッドがmethod()、同期ブロックを離れてstaticVar2他のスレッドにフラッシュすることを意味しますが、そうではありません staticVar1。正しいですか?

また、 では、別のスレッドが実行されている場合method2()、同期をdifferentLock行うと、事前発生後発生の問題が発生する可能性がありますmethod()。ただし、問題は視認性です。スレッドAが実行さmethodれ、その後スレッドBが実行された場合、2 つのスレッドが同じロックを介して同期していなくても、AからBに発行されmethod2()た値は?staticVar2

static int staticVar1, staticVar2;
void method() {
    staticVar1++;
    synchronized (lock) {
        staticVar2++;
    }
}
void method2() {
    synchronized (differentLock) {
        staticVar2++;
    }
}

静的な質問

が他のスレッドに更新されない場合staticVar1、プログラム内のすべての静的変数は宣言を必要とするか、ブロックvolatile内でのみアクセスする必要があるようです。synchronizedかなり厳しいように見えますが、正しいですか?私の時代に、同期されていない静的変数がたくさんあるのを見たことがあります。

要約すれば

  1. 揮発性の読み取り/書き込みは、すべてのメモリをすべてのスレッドにフラッシュしますか、それともアクセスしている 2 つのスレッド間のみにフラッシュしますか? 答えが何であれ、すべてのメモリがフラッシュされるか、揮発性変数のみがフラッシュされますか?
  2. 同期されたブロックを終了するときに変更されたすべてのメモリがフラッシュされますか、それともブロック内で変更されたメモリだけですか? すべてのメモリがフラッシュされていない場合、値を確認するには、スレッドが同期するロック オブジェクトが同じである必要がありますか (つまり、ロック オブジェクトはメモリの可視性に何らかの影響を与えますか)?
  3. 2 つのスレッドがアクセスするすべての静的変数を同期する必要がありますか?
4

1 に答える 1

6

メモリに関するスコープの制限はありません。読み取りバリアまたは書き込みバリアがある場合、すべてのメモリの読み取り/書き込みに適用されます。

私が見た制限は、メモリ マッピングにあります。ファイルをメモリ マップするときは、別のスレッドでこれを使用できるようにする方法に注意する必要があります。これは、この新しいメモリ マッピングが別のスレッドですぐに表示されず、BUS エラー (および JVM のクラッシュ) が発生する可能性があるためです。 Linux と Windows の最新バージョンにはこの問題がないように見えるため、OS のバグです。

これは、次のコードで、method() を実行している 2 つのスレッドが同期ブロックを離れると、staticVar2 を他のスレッドにフラッシュしますが、staticVar1 にはフラッシュしないことを意味します。正しいですか?

statixVar1 は、staticVar2 がおそらくより早くフラッシュされるときに常にフラッシュされます。いつという保証はありませんが、順番は保証されています。

スレッド A がメソッドを実行し、その後スレッド B が method2() を実行する場合、2 つのスレッドが同じロックを介して同期していなくても、A から B に発行された staticVar2 の値ですか?

はい、使用されるロックは、発生前の保証には関係ありません。

揮発性の読み取り/書き込みは、すべてのメモリをすべてのスレッドにフラッシュしますか、それともアクセスしている 2 つのスレッド間のみにフラッシュしますか? 答えが何であれ、すべてのメモリがフラッシュされるか、揮発性変数のみがフラッシュされますか?

すべてのダーティ メモリは書き込みバリアでフラッシュされ、すべての読み取りは読み取りバリアで一貫した順序になります。 volatile書き込みの書き込みバリアと読み取りの読み取りバリアの両方を実行します。

同期されたブロックを終了するときに、変更されたすべてのメモリがフラッシュされますか、それともブロック内で変更されたメモリだけですか?

そのスレッドによって変更されたすべてのメモリ。

2 つのスレッドがアクセスするすべての静的変数を同期する必要がありますか?

1 つのスレッドが変数を変更する場合のみ。任意の数のスレッドが同期なしで静的値を読み取ることができます。

于 2013-06-11T10:06:02.700 に答える