public interface Lock
Lock
実装は、synchronized
のメソッドや文を使用することで取得可能なロック操作よりも広範なロック操作を提供します。この実装を使用すると、より柔軟な構築を行なったり、まったく異なるプロパティーを保持したり、関連する複数の Condition
オブジェクトをサポートしたりできるようになります。
ロックは、複数のスレッドによる共有リソースへのアクセスを制御するためのツールです。通常、ロックは共有リソースへの排他的なアクセスを提供します。ロックを取得できるのは一度に 1 つのスレッドだけであり、すべての共有リソースにアクセスするにはロックを最初に取得する必要があります。ただし、ReadWriteLock
の読み込みロックなどの一部のロックでは、共有リソースへの並行アクセスが許可される場合があります。
synchronized
メソッドまたは文の使用により、すべてのオブジェクトに関連付けられた暗黙の監視ロックへのアクセスが提供されますが、ロックの取得と解放のすべてをブロック構造に従って行うことが求められます。このため、複数のロックが取得された場合、その解放は取得とは反対の順序で行う必要があります。また、すべてのロックの解放は、それらが取得された範囲内で行う必要があります。
synchronized
メソッドおよび文の範囲メカニズムによって、監視ロックのプログラミングがはるかに容易になり、ロックに関連した一般的なプログラミングエラーの多くが回避しやすくなる一方で、ロックをより柔軟な方法で操作することが必要な状況も発生します。たとえば、並行してアクセスされるデータ構造をトラバースするための一部のアルゴリズムでは、「hand-over-hand」または「chain locking」の使用が必要になります。この場合、ノード A のロックを取得し、次にノード B のロックを取得し、次に A を解放して C を取得し、次に B を解放して D を取得する、という具合に処理を進めます。Lock
インタフェースの実装により、ロックを異なるスコープ内で取得および解放したり、複数のロックを任意の順序で取得および解放したりできるようにすることで、このようなテクニックの使用が可能になります。
このように柔軟性が高まると、新たな責任も発生します。ブロック構造ロックが存在しなくなることで、synchronized
メソッドおよび文で実行されるロックの自動解放が機能しなくなります。たいていの場合、次のコードを使用する必要があります。
Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }ロックおよびロック解除が異なるスコープ内で行われる場合、ロックの保持中に実行されるすべてのコードが try-finally または try-catch により保護され、必要に応じてロックが確実に解放されるように注意を払う必要があります。
Lock
実装は、ロックを取得するための非ブロック試行 (tryLock()
)、割り込み可能なロックを取得するための試行 (lockInterruptibly()
)、およびタイムアウト可能なロックを取得するための試行 (tryLock(long, TimeUnit)
) を提供することによって、synchronized
メソッドおよび文の使用に対する追加機能を提供します。
Lock
クラスは、保証された順序付け、再入不可能な使用、デッドロックの検出など、暗黙の監視ロックとはまったく異なる動作やセマンティクスを提供できます。実装がこうした特殊セマンティクスを提供する場合、実装はこれらのセマンティクスをドキュメント化する必要があります。
Lock
インスタンスは、通常のオブジェクトであるため、それ自体を synchronized
文のターゲットとして使用できることに注意してください。Lock
インスタンスの監視ロックの取得と、そのインスタンスのいずれかの lock()
メソッドの呼び出しとの間に指定された関係はありません。混乱を避けるために、独自の実装内で行う場合を除き、Lock
インスタンスをこの方法では決して使用しないようにすることをお勧めします。
特に記載がないかぎり、パラメータに null
値を渡すと NullPointerException
がスローされます。
すべての Lock
実装は、『Java™ 言語仕様』のセクション 17.4 に記載されているように、組み込み監視ロックが提供するのと同じメモリー同期セマンティクスを適用する必要があります。
lock
操作には、成功した Lock アクションと同じメモリー同期効果がある。
unlock
操作には、成功した Unlock アクションと同じメモリー同期効果がある。
ロック取得の 3 つの形式 (割り込み可、割り込み不可、および時間指定) では、パフォーマンス特性、順序付けの保証、ほかの実装品質が異なります。さらに、進行中のロック取得への割り込み機能も、特定の Lock
クラスでは使用できない可能性があります。このため、3 つのロック取得形式すべてで、実装が厳密に同じ保証やセマンティクスを定義する必要はありません。また、進行中のロック取得の割り込みをサポートする必要もありません。実装は、各ロックメソッドの提供するセマンティクスおよび保証を明確にドキュメント化する必要があります。また、ロック取得の割り込みがサポートされる範囲内 (全体またはメソッドエントリのみ) で、このインタフェースで定義された割り込みセマンティクスに従う必要もあります。
通常、割り込みは取り消しを意味し、割り込みのチェックは頻繁に行われるものではないため、実装は通常のメソッド復帰に対する割り込みに肯定的に応答できます。これは、別のアクションがスレッドをブロック解除したあとに、割り込みが発生したことが示される場合にも当てはまります。実装は、この動作をドキュメント化する必要があります。
ReentrantLock
, Condition
, ReadWriteLock
修飾子と型 | メソッドと説明 |
---|---|
void |
lock()
ロックを取得します。
|
void |
lockInterruptibly()
現在のスレッドに対して割り込みが発生していないかぎり、ロックを取得します。
|
Condition |
newCondition()
この
Lock インスタンスにバインドされた新しい Condition インスタンスを返します。 |
boolean |
tryLock()
呼び出し時にロックされていない場合にのみ、ロックを取得します。
|
boolean |
tryLock(long time, TimeUnit unit)
指定された待機時間内でロックが利用可能であり、現在のスレッドで割り込みが発生していない場合に、ロックを取得します。
|
void |
unlock()
このロックを解除します。
|
void lock()
ロックを使用できない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、ロックが取得されるまで待機します。
実装上の考慮事項
Lock
実装は、デッドロックを引き起こす呼び出しなどのロックの不正使用を検出し、そのような状況で (チェックされない) 例外をスローできます。Lock
実装により、該当する状況および例外の型をドキュメント化する必要があります。
void lockInterruptibly() throws InterruptedException
利用可能な場合にロックを取得して、すぐに復帰します。
ロックを使用できない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、次の 2 つのいずれかが起きるまで待機します。
現在のスレッドで、
InterruptedException
がスローされ、現在のスレッドの割り込みステータスがクリアされます。
実装上の考慮事項
ある状況下ではロック取得に割り込むことができず、場合によっては負荷の大きい操作になる場合があります。プログラマは、このような場合があることを意識しておく必要があります。実装は、該当する状況をドキュメント化する必要があります。
実装は、通常のメソッド復帰に対する割り込みに肯定的に応答できます。
Lock
実装は、デッドロックを引き起こす呼び出しなどのロックの不正使用を検出し、そのような状況で (チェックされない) 例外をスローできます。Lock
実装により、該当する状況および例外の型をドキュメント化する必要があります。
InterruptedException
- 現在のスレッドがロックの取得中に割り込まれた (かつ、ロック取得の割り込みがサポートされている) 場合。boolean tryLock()
使用可能な場合はロックを取得し、ただちに値 true
で復帰します。ロックが使用できない場合、このメソッドはただちに値 false
で復帰します。
このメソッドの通常の使用方法を次に示します。
Lock lock = ...; if (lock.tryLock()) { try { // manipulate protected state } finally { lock.unlock(); } } else { // perform alternative actions }この使用により、ロックが取得された場合にロックが解除されること、およびロックが取得されなかった場合にロック解除を試みないことが保証されます。
true
。それ以外の場合は false
boolean tryLock(long time, TimeUnit unit) throws InterruptedException
ロックが使用可能な場合、このメソッドはただちに値 true
で復帰します。ロックが利用できない場合、現在のスレッドがスレッドスケジューリングに関して無効になり、次の 3 つのいずれかが起きるまで待機します。
ロックが取得された場合は、値 true
が返されます。
現在のスレッドで、
InterruptedException
がスローされ、現在のスレッドの割り込みステータスがクリアされます。
指定された待機時間が経過すると、値 false
が返されます。時間がゼロまたはそれより小さい場合、メソッドは待機しません。
実装上の考慮事項
ある状況下ではロック取得に割り込むことができず、場合によっては負荷の大きい操作になる場合があります。プログラマは、このような場合があることを意識しておく必要があります。実装は、該当する状況をドキュメント化する必要があります。
実装は、通常のメソッド復帰に対する割り込み、またはタイムアウトのレポートに肯定的に応答できます。
Lock
実装は、デッドロックを引き起こす呼び出しなどのロックの不正使用を検出し、そのような状況で (チェックされない) 例外をスローできます。Lock
実装により、該当する状況および例外の型をドキュメント化する必要があります。
time
- ロックの最長待機時間unit
- time
引数の時間単位true
。ロックが取得される前に待機時間が経過した場合は false
InterruptedException
- 現在のスレッドがロックの取得中に割り込まれた (かつ、ロック取得の割り込みがサポートされている) 場合void unlock()
実装上の考慮事項
通常、Lock
実装は、ロックを解放可能なスレッドに関して制限を課し (一般に、ロックのホルダーだけが解放できる)、制限が侵された場合には (チェックされない) 例外をスローできます。Lock
実装により、すべての制限および例外の型をドキュメント化する必要があります。
Condition newCondition()
Lock
インスタンスにバインドされた新しい Condition
インスタンスを返します。
状態の待機を実行する前に、現在のスレッドがロックを保持する必要があります。Condition.await()
への呼び出しにより、待機の前にロックを原子的に解放し、待機が復帰する前にロックを再取得します。
実装上の考慮事項
Condition
インスタンスの正確な操作は Lock
実装に依存するため、その実装によってドキュメント化される必要があります。
Lock
インスタンス用の新規 Condition
インスタンスUnsupportedOperationException
- この Lock
実装が状態をサポートしていない場合 バグまたは機能を送信
詳細な API リファレンスおよび開発者ドキュメントについては、Java SE のドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright © 1993, 2013, Oracle and/or its affiliates. All rights reserved.