この質問は、メモリの可視性のみに関連しており、発生前および発生後ではありません。Java には、あるスレッドのメモリへの変更が別のスレッドから見えるようにすることを保証する 4 つの方法があります。(参照http://gee.cs.oswego.edu/dl/cpj/jmm.html )
- 書き込みスレッドが同期ロックを解放し、その後、読み取りスレッドが同じ同期ロックを取得します。
- フィールドが volatile として宣言されている場合、書き込みスレッドがさらにメモリ操作を実行する前に、そのフィールドに書き込まれた値はすべてフラッシュされ、書き込みスレッドによって可視になります (つまり、当面の目的のためにすぐにフラッシュされます)。
- スレッドがオブジェクトのフィールドに初めてアクセスすると、フィールドの初期値か、他のスレッドによって書き込まれた後の値が表示されます。
- スレッドが終了すると、書き込まれたすべての変数がメイン メモリにフラッシュされます。
Java Concurrency in Practice によると、そのような質問に関する聖書:
volatile 変数の可視性効果は、volatile 変数自体の値を超えて拡張されます。スレッドAが揮発性変数に書き込み、続いてスレッドBが同じ変数を読み取ると、揮発性変数に書き込む前にAに表示されていたすべての変数の値は、揮発性変数を読み取った後にBに表示されます。
揮発性の質問
これは、 AからCではなく A から B にメモリをフラッシュする方法を知るために、JVM が実際に volatile 変数の読み取りと書き込みを追跡することを意味しますか? したがって、 Aが変数に書き込み、後でCが変数から読み取り、その後Bが変数から読み取り、フラッシュはAとBおよびAとCの間でスレッドごとに行われますが、BとCは行われませんか? または、スレッドに関係なく、キャッシュされたすべてのメモリがフラッシュされることを意味しますか? 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
かなり厳しいように見えますが、正しいですか?私の時代に、同期されていない静的変数がたくさんあるのを見たことがあります。
要約すれば
- 揮発性の読み取り/書き込みは、すべてのメモリをすべてのスレッドにフラッシュしますか、それともアクセスしている 2 つのスレッド間のみにフラッシュしますか? 答えが何であれ、すべてのメモリがフラッシュされるか、揮発性変数のみがフラッシュされますか?
- 同期されたブロックを終了するときに変更されたすべてのメモリがフラッシュされますか、それともブロック内で変更されたメモリだけですか? すべてのメモリがフラッシュされていない場合、値を確認するには、スレッドが同期するロック オブジェクトが同じである必要がありますか (つまり、ロック オブジェクトはメモリの可視性に何らかの影響を与えますか)?
- 2 つのスレッドがアクセスするすべての静的変数を同期する必要がありますか?