この待機宣言があると:
public final native void wait(long timeout) throws InterruptedException;
それは、InterruptedException、またはタイムアウト、または別のスレッドでNotify/NotifyAllメソッドが呼び出されたために終了する可能性があり、例外は簡単にキャッチできますが...
出口の原因がタイムアウトか通知かを知る方法はありますか?
編集:
これはうまくいくかもしれないトリッキーな方法です(私はそれが好きではありませんが)
long tBefore=System.currentTimeMillis();
wait(TIMEOUT);
if ((System.currentTimeMillis() - tBefore) > TIMEOUT)
{
//timeout
}
追加のコードを提供しない限り、2つを区別することはできません。たとえば、ThreadLocal
Boolean
を追加することにより、notify()
でのみtrue
に設定されます
ただし、最初に、ロジックにこの差別化が必要であることを確認する必要があります。
Notifyが戻る可能性があるもう1つの理由があります。それは偽のウェイクアップです。一部のハードウェアとOSの組み合わせでは、偽のウェイクアップを防ぐのは非常にコストがかかるため、これはありそうもないことですが、可能性のあることです。
このため、常にループ内でwait()を呼び出し、待機している条件を再確認する必要があります。この作業中に、同時にタイムアウトを確認するのは簡単です。
詳細については、「Java Concurrency In Practice」という本をお勧めします。そして、あなたのためにこれをすべて正しくするより高いレベルの構造を使用します。
これは質問に正確に答えるものではありませんが、おそらく問題を解決します。より高いレベルの同時実行メカニズムを使用します。待機/通知は、他の多くの理由から、通常、必要なレベルよりも低いレベルです。
たとえば、 BlockingQueue.poll(long, TimeUnit)
を使用している場合、タイムアウトしたかどうかを確認するために結果がnullかどうかを確認できます。
System.currentTimeMillis()
を使用せず、代わりにSystem.nanoTime()
を使用してください。
最初のものは、(システムクロックに基づいて)絶対時間を測定します。システム時間を変更すると、奇妙な結果になる可能性があります。例:時計を1時間遅らせた場合、5秒の待機時間は1時間になります。時計を進めた場合、0秒後に10分の待機が行われます。
2つ目は、相対時間を測定します。常に一定の速度で一方向に実行されますただし、原点はありません。つまり、値は相対時間の測定にのみ使用できますが、日付の決定には使用できません。
直接伝える方法はありません-つまり、これを確認するには、コードを追加する必要があります。多くの場合、wait()は、オブジェクトの状態を何らかの方法で変更する何かが発生するのを待っています-たとえばおそらくブール変数を設定することによって。その場合は、変数の状態をチェックして、イベントが発生したかどうか、または単にタイムアウトしたかどうかを確認できます。または、System.currentTimeMillis()の値を調べて、経過時間がタイムアウト期間以上であることを確認できます-タイムアウト期間である場合、それはおそらくタイムアウトした手がかりになります(絶対的な保証ではありませんが) )。または、経過時間がタイムアウト期間よりも短い場合は、タイムアウトしていません。それは役に立ちますか?
待機/通知しないアプローチを使用する必要があります。
条件付きのロックを使用する方が良いでしょう https://docs.Oracle.com/javase/8/docs/api/Java/util/concurrent/locks/Condition.html#await-long-Java.util。 concurrent.TimeUnit-
タイムアウトで待機し、メソッドから戻る前に検出可能な待機時間が経過した場合はfalseを返し、そうでない場合はtrueを返します。
通知時に例外がスローされず、タイムアウトしません。
Object.wait()
を使用するよりも、Java.lang.concurrent
パッケージ同期オブジェクトに依存する方が良いと思います。