私のクラスはスレッドセーフですか?そうでない場合はなぜですか?
class Foo {
boolean b = false;
void doSomething() throws Exception {
while (b) Thread.sleep();
}
void setB(boolean b) {
this.b = b;
}
}
私のクラスはスレッドセーフですか?そうでない場合はなぜですか?
class Foo {
boolean b = false;
void doSomething() throws Exception {
while (b) Thread.sleep();
}
void setB(boolean b) {
this.b = b;
}
}
実行中のスレッドは、コードがコンパイルされるまで(後でランダムな時点になる可能性があります)変更が表示され、変更が表示されなくなる可能性があるため、コードはスレッドセーフではありません。
ところで:これはテストを行うのを非常に難しくします。たとえば、1秒間寝ると、この動作が3時間近く見られない場合があります。
つまり、機能する場合と機能しない場合があり、機能したからといって機能し続けるとは言えません。
JITは最適化できb
ないため、最適化できます。volatile
while (b) Thread.sleep(N);
することが
boolean b = this.b;
if (b) while (true) Thread.sleep(N);
したがって、の値はb
毎回読み取られるわけではありません。
そうではない。インスタンス変数値をsetB()
更新していますが、ではありません。b
synchronized
複数のスレッドがsetB()
同時にメソッドを実行しようとすると、予期しない結果が生じる可能性があります。
オブジェクトをロックsynchronize
するメソッド(または)を使用する必要があります。synchronize
this
AtomicBooleanを見てください。これは、一度に1つのスレッドのみがアクセスできることを意味します。
しかし、それはスレッドセーフとどのように関係していますか?少し混乱しました。
「スレッドセーフ」の定義に戻ります。ウィキペディアはこれを言います:
「スレッドセーフは、マルチスレッドプログラムのコンテキストに適用できるコンピュータプログラミングの概念です。複数のスレッドによる同時実行中に正しく機能する場合、コードの一部はスレッドセーフです。」
ここで重要なのは、正しく機能することです。Peter Lawreyによって説明されたシナリオを見ると、JITコンパイルにより、値がからにb
変更されたときに気付かず、代わりに永遠にループするコードが生成される可能性があることがわかります。これは明らかに間違った動作です。また、これは2つのスレッドがある場合にのみ発生するため、スレッドセーフの問題です。true
false
ここで問題となる概念は可視性であり、並行Javaで説明されています。doSomething()が別のスレッドで実行されている場合、JVMは、setBで実行されたアクションがdoSomethingが認識するバージョンbに適用されることを保証しません。したがって、setBを呼び出すことができ、doSomethingが終了することは保証されません。