モジュール java.base

インタフェースLock

既知のすべての実装クラス:
ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock

public interface Lock
Lock実装は、synchronizedのメソッドや文を使用することで取得可能なロック操作よりも広範なロック操作を提供します。 この実装を使用すると、より柔軟な構築を行ったり、まったく異なるプロパティを保持したり、関連する複数のConditionオブジェクトをサポートしたりできるようになります。

ロックは、複数のスレッドによる共有リソースへのアクセスを制御するためのツールです。 通常、ロックは共有リソースへの排他的なアクセスを提供します。ロックを取得できるのは一度に1つのスレッドだけであり、すべての共有リソースにアクセスするにはロックを最初に取得する必要があります。 ただし、ReadWriteLockの読込みロックなどの一部のロックでは、共有リソースへの並行アクセスが許可される場合があります。

synchronizedメソッドまたは文の使用により、すべてのオブジェクトに関連付けられた暗黙の監視ロックへのアクセスが提供されますが、ロックの取得と解放のすべてをブロック構造に従って行うことが求められます。このため、複数のロックが取得された場合、その解放は取得とは反対の順序で行う必要があります。また、すべてのロックの解放は、それらが取得された範囲内で行う必要があります。

synchronizedメソッドおよび文の範囲メカニズムによって、監視ロックのプログラミングがはるかに容易になり、ロックに関連した一般的なプログラミング・エラーの多くが回避しやすくなる一方で、ロックをより柔軟な方法で操作することが必要な状況も発生します。 For example, some algorithms for traversing concurrently accessed data structures require the use of "hand-over-hand" or "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章 で説明されているとおり、組込みのモニター・ロックで提供されているものと同じメモリー同期セマンティクスを強制する必要があります:

  • 成功したlock操作には、成功したLockアクションと同じメモリー同期効果がある。
  • 成功したunlock操作には、成功したUnlockアクションと同じメモリー同期効果がある。
成功しないロックおよびロック解除操作、および再入可能なロック/ロック解除操作は、メモリー同期効果を一切必要としません。

実装上の考慮事項

ロック取得の3つの形式(割込み可、割込み不可、および時間指定)では、パフォーマンス特性、順序付けの保証、ほかの実装品質が異なります。 さらに、進行中のロック取得への割込み機能も、特定のLockクラスでは使用できない可能性があります。 このため、3つのロック取得形式すべてで、実装が厳密に同じ保証やセマンティックスを定義する必要はありません。また、進行中のロック取得の割込みをサポートする必要もありません。 実装は、各ロック・メソッドの提供するセマンティックスおよび保証を明確にドキュメント化する必要があります。 また、ロック取得の割込みがサポートされる範囲内(全体またはメソッド・エントリのみ)で、このインタフェースで定義された割込みセマンティックスに従う必要もあります。

通常、割込みは取消しを意味し、割り込みのチェックは頻繁に行われるものではないため、実装は通常のメソッド復帰に対する割り込みに肯定的に応答できます。 これは、別のアクションがスレッドをブロック解除したあとに、割込みが発生したことが示される場合にも当てはまります。 実装は、この動作をドキュメント化する必要があります。

Java言語仕様を参照してください:
17.4 メモリー・モデル
導入されたバージョン:
1.5
関連項目: