私はSystem.out.println()
、コードをスレッドセーフにすることを主張する多くの投稿を読んだので、レースをシミュレートするにSystem.out.println()
は、コードから削除する必要があります。
これで、ストリームに書き込む前write()
にPrintStream
同期するメソッドがオンthis
になるため、write()
呼び出されるたびにロックが保持され、解放されます。
write()
PrintStreamのメソッド
public void write(int b) {
try {
synchronized (this) { //acquires a lock
ensureOpen();
out.write(b);
if ((b == '\n') && autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
しかし、それは人種の行動に影響を及ぼしますか?
仮定:
boolean flag = true;
Thread 1:
System.out.println();
flag = false;
System.out.println();
Thread 2:
System.out.println();
while(flag){
System.out.println();
}
これで、両方のスレッドが同じオブジェクト、つまりthis
(PrintStream)をロックしていることがわかります。これは、同じロックを取得および解放しているflag
2つの間に含まれているためsysouts
、flag
値はキャッシュからフラッシュされ、メモリ内で更新されます。スレッドはそれを見ることができます。
したがって、レースのシミュレーションは難しいので、このコードがスレッドセーフになり、スレッド2が変更を確認するという理論上の可能性はありflag
ますか?
はいの場合、同じ効果をvolatile
使用して達成できSystem.out.println();
ますか?
JLSには、このトピックについて次のように述べています。An unlock on a monitor happens-before every subsequent lock on that monitor.
(17.4.5)
JLSで発生前などの正確な定義を読み取ることができますが、これは基本的に、ロックを解除する前にスレッドで発生したすべての読み取りと書き込みが、ロックを取得する別のスレッドによって認識されることを意味します。 (注意!ロックを取得せずにフラグに書き込んだスレッド3があった場合、同期は必要ありません)
この場合、同じオブジェクトをロックしているので、これは、はい、更新されたflag
値がスレッド2によって認識される必要があることが保証されていることを意味します。
PrintStreamがロックを取得し、スレッドセーフに使用できることが保証されていることについてはドキュメントに記載されていませんが、ここでは実装の詳細に依存しています(ただし、壊れることはほとんどありません)。 )。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加