public interface Condition
Condition は、Object 監視メソッド (wait、notify、および notifyAll) を別個のオブジェクトに分解し、それらに任意の Lock 実装の使用を組み合わせて、オブジェクトごとに複数の待機セットを保持する効果を付与します。ここで、Lock は synchronized メソッドおよび文の使用を置き換え、Condition は Object 監視メソッドの使用を置き換えます。
状態 (状態キューまたは状態変数とも呼ばれる) は、何らかの状態が true になっている可能性があることが別のスレッドによって通知されるまで、スレッドが実行を中断 (「待機」) するための手段を提供します。この共有状態情報へのアクセスは別のスレッド内で行われるため、このアクセスを保護する必要があります。このため、なんらかの形式のロックがこの状態と関連付けられています。状態の待機によって提供される主な特性は、Object.wait と同様に、関連付けられたロックを原子的に解放し、現在のスレッドを中断することです。
Condition インスタンスは、本質的にロックにバインドされています。特定の Lock インスタンスのための Condition インスタンスを取得するには、その newCondition() メソッドを使用します。
例として、put メソッドと take メソッドをサポートするバウンドバッファーがあるとします。空のバッファーに対して take が試行された場合は、項目が使用可能になるまでスレッドがブロックされます。いっぱいのバッファーに対して put が試行された場合は、容量が使用可能になるまでスレッドがブロックされます。バッファー内で項目または容量が使用可能になったときに 1 回につき 1 つのスレッドにのみ通知する最適化を使用できるように、put スレッドと take スレッドを個別の待機セット内で待機した状態に維持することにします。これは、2 つの Condition インスタンスを使用して実現できます。
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
(ArrayBlockingQueue クラスにはこの機能があるため、この使用例のクラスを実装する必要はありません。)
Condition 実装は、通知の順序付けが保証されることや、通知の実行時にロックを保持する必要がないことなど、Object 監視メソッドとは異なる動作やセマンティクスを提供できます。実装がこうした特殊セマンティクスを提供する場合、実装はこれらのセマンティクスをドキュメント化する必要があります。
Condition インスタンスは、通常のオブジェクトであるため、それ自体を synchronized 文のターゲットとして使用できることや、独自の監視 wait および notification メソッドが呼び出されるようにできることに注意してください。Condition インスタンスの監視ロックの取得、またはその監視メソッドの使用は、その Condition に関連付けられた Lock の取得または、その待機および信号送信メソッドの使用とは特に関係がありません。混乱を避けるために、独自の実装内で行う場合を除き、Condition インスタンスをこの方法では決して使用しないようにすることをお勧めします。
特に記載がないかぎり、パラメータに null 値を渡すと NullPointerException がスローされます。
Condition の待機中に、基本となるプラットフォームセマンティクスへの譲歩として、通常、「見せかけの起動」が許可されます。Condition は、ループ上で常に待機して、待機対象の状態予測をテストする必要があるため、これはたいていのアプリケーションプログラムでは実質的な効果はほとんどありません。実装は見せかけの起動の可能性を自由に削除できますが、アプリケーションプログラマはそれが発生し、ループ上で常に待機するものと想定することをお勧めします。
状態待機の 3 つの形式 (割り込み可、割り込み不可、および時間指定) では、プラットフォームでの実装の容易性およびパフォーマンス特性が異なります。特に、これらの機能を提供しつつ、順序付け保証などの特定のセマンティクスを維持することが困難な場合があります。さらに、実際のスレッド中断に割り込む機能をすべてのプラットフォームで実装することは、常に実行可能であるとは限りません。
したがって、実装が、3 つの待機形式すべてで同一の保証やセマンティクスを定義することは要求されていません。また、実際のスレッド中断に対する割り込みをサポートする必要もありません。
実装は、待機中の各メソッドで提供されるセマンティクスや保証、および実装がスレッド中断の割り込みをサポートし、このインタフェースで定義された割り込みセマンティクスに従う必要がある場合を明確にドキュメント化する必要があります。
通常、割り込みは取り消しを意味し、割り込みのチェックは頻繁に行われるものではないため、実装は通常のメソッド復帰に対する割り込みに肯定的に応答できます。これは、スレッドをブロック解除した可能性のある別のアクションのあとに割り込みが発生したことが示される場合でも当てはまります。実装は、この動作をドキュメント化する必要があります。
| 修飾子と型 | メソッドと説明 |
|---|---|
void |
await()
信号が送信されるか、割り込みが発生するまで、現在のスレッドを待機させます。
|
boolean |
await(long time, TimeUnit unit)
信号が送信される、割り込みが発生する、または指定された待機時間が経過するまで、現在のスレッドを待機させます。
|
long |
awaitNanos(long nanosTimeout)
信号が送信される、割り込みが発生する、または指定された待機時間が経過するまで、現在のスレッドを待機させます。
|
void |
awaitUninterruptibly()
現在のスレッドを、信号が送られるまで待機させます。
|
boolean |
awaitUntil(Date deadline)
信号が送信される、割り込みが発生する、または指定された期限が経過するまで、現在のスレッドを待機させます。
|
void |
signal()
待機中のスレッドを 1 つ起動します。
|
void |
signalAll()
待機中のすべてのスレッドを起動します。
|
void await()
throws InterruptedException
この Condition に関連付けられているロックは原子的に解放されます。また、現在のスレッドはスレッドのスケジューリングとしては無効になり、次の 4 つのいずれかが起きるまで待機します。
Condition に対して signal() メソッドを呼び出し、現在のスレッドが起動スレッドとして選択される。
Condition に対して signalAll() メソッドを呼び出した
いずれの場合でも、このメソッドが現在のスレッドを返す前に、この状態に関連付けられたロックを再取得する必要があります。スレッドの復帰時に、このロックを保持することが保証されます。
現在のスレッドで、
InterruptedException がスローされ、現在のスレッドの割り込みステータスがクリアされます。初回時には、ロックが解放される前に割り込みのテストが実行されるかどうかは指定されません。
実装上の考慮事項
このメソッドの呼び出し時に、現在のスレッドは、この Condition に関連付けられているロックを保持するものとみなされます。これが応答方法を決定する要因になるかどうかは、実装によって異なります。通常、(IllegalMonitorStateException などの) 例外がスローされ、実装はそのことをドキュメント化する必要があります。
実装は、信号に応答して実行される通常のメソッド復帰に対する割り込みに肯定的に応答できます。この場合、実装は、別の待機スレッドが存在する場合に、信号がそのスレッドに確実にリダイレクトされるようにする必要があります。
InterruptedException - 現在のスレッドで割り込みが発生する (およびスレッド中断の割り込みがサポートされる) 場合void awaitUninterruptibly()
この状態に関連付けられているロックは原子的に解放されます。また、現在のスレッドはスレッドのスケジューリングとしては無効になり、次の 3 つのいずれかが起きるまで待機します。
Condition に対して signal() メソッドを呼び出し、現在のスレッドが起動スレッドとして選択される。
Condition に対して signalAll() メソッドを呼び出した
いずれの場合でも、このメソッドが現在のスレッドを返す前に、この状態に関連付けられたロックを再取得する必要があります。スレッドの復帰時に、このロックを保持することが保証されます。
現在のスレッドがこのメソッドに入るときにその割り込み状態が設定されるか、または待機中に割り込みが発生する場合は、信号が送信されるまで待機が継続されます。このメソッドからの最終復帰時にも、「割り込み状態」は引き続き設定されます。
実装上の考慮事項
このメソッドの呼び出し時に、現在のスレッドは、この Condition に関連付けられているロックを保持するものとみなされます。これが応答方法を決定する要因になるかどうかは、実装によって異なります。通常、(IllegalMonitorStateException などの) 例外がスローされ、実装はそのことをドキュメント化する必要があります。
long awaitNanos(long nanosTimeout)
throws InterruptedException
この状態に関連付けられているロックは原子的に解放されます。また、現在のスレッドはスレッドのスケジューリングとしては無効になり、次の 5 つのいずれかが起きるまで待機します。
Condition に対して signal() メソッドを呼び出し、現在のスレッドが起動スレッドとして選択される。
Condition に対して signalAll() メソッドを呼び出した
いずれの場合でも、このメソッドが現在のスレッドを返す前に、この状態に関連付けられたロックを再取得する必要があります。スレッドの復帰時に、このロックを保持することが保証されます。
現在のスレッドで、
InterruptedException がスローされ、現在のスレッドの割り込みステータスがクリアされます。初回時には、ロックが解放される前に割り込みのテストが実行されるかどうかは指定されません。
このメソッドは、復帰時に、指定された nanosTimeout 値に対する待機する残りの推定ナノ秒数を返します。または、タイムアウトした場合はゼロ以下の値を返します。待機が復帰しても待機状態が依然として保持されない場合に、この値を使用して、再度待機するかどうか、およびその期間を決定できます。通常、このメソッドは次の形式になります。
boolean aMethod(long timeout, TimeUnit unit) {
long nanos = unit.toNanos(timeout);
lock.lock();
try {
while (!conditionBeingWaitedFor()) {
if (nanos <= 0L)
return false;
nanos = theCondition.awaitNanos(nanos);
}
// ...
} finally {
lock.unlock();
}
}
設計上の注意:このメソッドは、残り時間をレポートする際に切り詰めエラーの発生を避けるためにナノ秒の引数を指定する必要があります。この精度が低下すると、待機時間の合計が、指定された再待機の発生時よりもシステム的に短くないことをプログラマが保証することが難しくなります。
実装上の考慮事項
このメソッドの呼び出し時に、現在のスレッドは、この Condition に関連付けられているロックを保持するものとみなされます。これが応答方法を決定する要因になるかどうかは、実装によって異なります。通常、(IllegalMonitorStateException などの) 例外がスローされ、実装はそのことをドキュメント化する必要があります。
実装は、信号に応答して実行される通常のメソッド復帰に対する割り込み、または指定された待機時間の経過指示に対する割り込みに肯定的に応答できます。どちらの場合も、実装は、別の待機スレッドが存在する場合に、信号がそのスレッドに確実にリダイレクトされるようにする必要があります。
nanosTimeout - ナノ秒単位の待機時間nanosTimeout 値から引いた推定数。正の値は、希望する時間だけ待機できるように、このメソッドの以後の呼び出しに対する引数として使用される。ゼロ以下の値は、時間が残っていないことを示す。InterruptedException - 現在のスレッドで割り込みが発生する (およびスレッド中断の割り込みがサポートされる) 場合boolean await(long time,
TimeUnit unit)
throws InterruptedException
awaitNanos(unit.toNanos(time)) > 0
time - 待機する最長時間unit - time 引数の時間単位false - メソッドからの復帰前に待機時間が経過したことが検出された場合。そうでない場合は trueInterruptedException - 現在のスレッドで割り込みが発生する (およびスレッド中断の割り込みがサポートされる) 場合boolean awaitUntil(Date deadline) throws InterruptedException
この状態に関連付けられているロックは原子的に解放されます。また、現在のスレッドはスレッドのスケジューリングとしては無効になり、次の 5 つのいずれかが起きるまで待機します。
Condition に対して signal() メソッドを呼び出し、現在のスレッドが起動スレッドとして選択される。
Condition に対して signalAll() メソッドを呼び出した
いずれの場合でも、このメソッドが現在のスレッドを返す前に、この状態に関連付けられたロックを再取得する必要があります。スレッドの復帰時に、このロックを保持することが保証されます。
現在のスレッドで、
InterruptedException がスローされ、現在のスレッドの割り込みステータスがクリアされます。初回時には、ロックが解放される前に割り込みのテストが実行されるかどうかは指定されません。
戻り値は、期限が経過したかどうかを示します。この値は次のように使用できます。
boolean aMethod(Date deadline) {
boolean stillWaiting = true;
lock.lock();
try {
while (!conditionBeingWaitedFor()) {
if (!stillWaiting)
return false;
stillWaiting = theCondition.awaitUntil(deadline);
}
// ...
} finally {
lock.unlock();
}
}
実装上の考慮事項
このメソッドの呼び出し時に、現在のスレッドは、この Condition に関連付けられているロックを保持するものとみなされます。これが応答方法を決定する要因になるかどうかは、実装によって異なります。通常、(IllegalMonitorStateException などの) 例外がスローされ、実装はそのことをドキュメント化する必要があります。
実装は、信号に応答して実行される通常のメソッド復帰に対する割り込み、または指定された期限の経過指示に対する割り込みに肯定的に応答できます。どちらの場合も、実装は、別の待機スレッドが存在する場合に、信号がそのスレッドに確実にリダイレクトされるようにする必要があります。
deadline - 待機する絶対時間false - 復帰時に期限が経過している場合。そうでない場合は trueInterruptedException - 現在のスレッドで割り込みが発生する (およびスレッド中断の割り込みがサポートされる) 場合void signal()
この状態で待機中のスレッドが存在する場合、1 つのスレッドが起動用に選択されます。そのスレッドは、そのあと、await から復帰する前にロックを再取得する必要があります。
実装上の考慮事項
実装では、このメソッドが呼び出されたとき、現在のスレッドがこの Condition に関連付けられたロックを保持することが必要になることがあります (通常は必要です)。実装では、この事前条件と、ロックが保持されない場合に実行されるアクションをドキュメント化する必要があります。通常、IllegalMonitorStateException などの例外がスローされます。
void signalAll()
この状態で待機中のスレッドが存在する場合、すべてのスレッドが起動されます。各スレッドは、await から復帰する前にロックを再取得する必要があります。
実装上の考慮事項
実装では、このメソッドが呼び出されたとき、現在のスレッドがこの Condition に関連付けられたロックを保持することが必要になることがあります (通常は必要です)。実装では、この事前条件と、ロックが保持されない場合に実行されるアクションをドキュメント化する必要があります。通常、IllegalMonitorStateException などの例外がスローされます。
バグまたは機能を送信
詳細な API リファレンスおよび開発者ドキュメントについては、Java SE のドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright © 1993, 2013, Oracle and/or its affiliates. All rights reserved.