揮発性ブール値 (有効と呼びましょう) がある場合、次のコードは Java でスレッドセーフですか?
if (valid)
return;
valid = true;
または、valid が false の場合にのみ true に設定されるため、同期する必要がありますか (したがって、valid のセットは現在の値に依存します)。
揮発性ブール値 (有効と呼びましょう) がある場合、次のコードは Java でスレッドセーフですか?
if (valid)
return;
valid = true;
または、valid が false の場合にのみ true に設定されるため、同期する必要がありますか (したがって、valid のセットは現在の値に依存します)。
これは同期する必要があります。これは、1 つのスレッドが有効と評価され、代入の前に実行を中断した場合、別のスレッドが来て、valid を true に設定する前に、valid を false としてチェックすると、2 つのスレッドがコードを実行することになります。 here から(おそらくこれは望ましくありません)。
AtomicBoolean を使用します。インスタンスの確認と設定を同時に行うことができます。
スレッドセーフではありません。しかし、これがコード全体であれば問題ありません。
編集:万能の優れた代替手段はAtomicBoolean
、低レベルの操作を使用して同期なしで条件付き更新を実現する です。
フラグへの 2 つの別個の (つまり、非アトミックな) アクセスがあるため、このスレッドがフラグに対して書き込み操作を行う唯一のスレッドでない限り、同期が必要です。それでも、将来の変更があった場合に備えて、同期をとっておくとよいでしょう。
あなたのコードはスレッドセーフではありませんが、安全に実行できるかどうかは、実際には他のコードに依存しています。
valid = true
次のコードを 1 つのスレッドで 1 回だけ実行する必要がありますか? false
その場合、任意の数のスレッドが の値を読み取り、valid
最終的に に設定する可能性があるため、コードは安全ではありませんtrue
。例えば:
if (valid)
return;
// Imagine every single one of your threads stops and blocks here.
// They will all wake up again and set valid to true and then
// execute the code to follow.
valid = true;
しかし、後のコードが任意のスレッドvalid = true
によって最大 1 回実行されることを保証したいだけであれば、問題ありません。しかし、それが必要な動作である場合は、他の方法でそれを達成します。その場合に使用すると、自分が何をしているのかわからないように見えるからです。たとえば、スレッド間で変数を共有せず、各スレッドがコードを 1 回だけ実行できるようにすることもできます。volatile
valid
また、同期と揮発性について推論しているときに疑わしい場合は、同期を使用してください。通常はより明確でありvolatile
、コードがどのように機能するかを簡単に推論できることを除けば、 を使用することで必要なものがすべて得られます。
スレッドセーフはシステム全体のプロパティです。コードの一部を分離して見て、それをスレッドセーフ/非セーフと呼ぶことはできません。他のスレッドがそれとどのように対話するか、および一貫性の要件は何かによって異なります。そうは言っても、ほとんどのスレッドセーフ設計には if() ブロックの代わりに while() ループがあるため、設計はおそらく間違っています:)