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)) > 0time - 待機する最長時間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, 2014, Oracle and/or its affiliates. All rights reserved.