Object.wait()
Java の呼び出しは while ループに入れるべきだと読んだことがあります。その理由は、このスレッドが起動される可能性があり、通知を待っていた状態が依然として false (偽の起動) であるためです。
どうですかObject.wait(long timeout)
。ここでは、指定された時間の経過後にタイムアウトする必要があるため、条件をループしたくありません。しかし、それをループに入れない場合、早期に起こされないようにするにはどうすればよいでしょうか?
Object.wait()
Java の呼び出しは while ループに入れるべきだと読んだことがあります。その理由は、このスレッドが起動される可能性があり、通知を待っていた状態が依然として false (偽の起動) であるためです。
どうですかObject.wait(long timeout)
。ここでは、指定された時間の経過後にタイムアウトする必要があるため、条件をループしたくありません。しかし、それをループに入れない場合、早期に起こされないようにするにはどうすればよいでしょうか?
しかし、それをループに入れない場合、早期に起こされないようにするにはどうすればよいでしょうか?
これは Java IMO の欠陥ですが、さまざまな OS バリアントでの基になるスレッド サポートの欠陥である可能性があります。Javaは待機がタイムアウトしたかどうかを知っていると思いますが、呼び出し元が条件を再テストし、特に時間をテストしない限り、それを理解する方法はありません。醜い。
wait(long timeout)
そのため、もwhile
ループに入れて、時間がタイムアウト期間を過ぎているかどうかをテストする必要があります。私はこれを達成する他の方法を知りません。
long timeoutExpiredMs = System.currentTimeMillis() + timeoutMs;
while (!condition) {
long waitMillis = timeoutExpiredMs - System.currentTimeMillis();
if (waitMillis <= 0) {
// timeout expired
break;
}
// we assume we are in a synchronized (object) here
object.wait(waitMillis);
// we might be improperly awoken here so we loop around to see if the
// condition is still true or if we timed out
}
これは、Java が Hoare スタイルのモニターではなく Mesa スタイルのモニターを使用しているためです。したがって、wait を while ループに入れる必要があります。次のWebページで「このため、通常、各待機操作をこのようにループで囲む必要があります」という文字列を検索してください。
http://en.wikipedia.org/wiki/Monitor_(synchronization)#Nonblocking_condition_variables
.Hoare スタイルのモニターであった場合は、待機することもできたはずです。Mesa モニターの詳細は近日中に追加します。これは Java の欠陥ではありません。どちらのタイプのモニターにも長所と短所があります。
long deadline = now() + timeout;
synchronized(lock)
while( !condition() && now()<deadline )
lock.wait( deadline - now() );
if(condition())
...
else // timeout
...
ループ内での待機の呼び出しは、時折の誤ったウェイクアップを処理するためだけではありません。複数のスレッドがロックをめぐって競合している一般的な (おもちゃではない例) ケースでは、スレッドが待機から復帰した時点で、待機前に行ったチェックでは、待機後のオブジェクトの状態を予測するのに十分ではありません。待機していたスレッドはロックを放棄したため、それ以降に何かが起こった可能性があります。さらに、通知がどのように機能するかについて原子的なことは何もありません。が作成され、通知されたスレッドがロックを再取得しました。
ロックを再取得したら、何が起こっているかを知るために現在の状態を確認する必要があるため、基本的にはループで待機します。タイムアウトがあってもそれは変わりません。タイムアウトは、通知が見逃された場合にスレッドが永久にハングしないようにするための安全メカニズムです。待機がタイムアウトした場合、通常、特定のアクションは必要ありません。ロックを再取得し、ループ本体に進み、通常どおり状態を確認してください。
これは Java のせいではありません。これが pthread のしくみです。