- java.lang.Object
-
- java.util.concurrent.locks.StampedLock
-
- すべての実装されたインタフェース:
Serializable
public class StampedLock extends Object implements Serializable
読取り/書込みアクセスを制御する3つのモードを持つ機能ベースのロックです。 StampedLockの状態はバージョンとモードから構成されます。 ロック取得メソッドは、ロック状態に対するアクセスを表現および制御するスタンプを返します。これらのメソッドのtryバージョンは、アクセスの取得失敗を表すために特殊な値ゼロを代わりに返す場合があります。 ロック解放メソッドとロック変換メソッドは、引数としてスタンプを必要とし、それらがロックの状態と一致しない場合は失敗します。 モードは次の3つです。- 書込み。
writeLock()
メソッドは、排他的アクセスを待機してブロックする可能性があり、ロックを解放するためにunlockWrite(long)
メソッドで使用できるスタンプを返します。 時間指定のないバージョンと時間指定のあるバージョンのtryWriteLock
も用意されています。 ロックが書込みモードで保持されているときは、読取りロックを取得することはできず、オプティミスティック読取り検証はすべて失敗します。 - 読取り。
readLock()
メソッドは、非排他的アクセスを待機してブロックする可能性があり、ロックを解放するためにunlockRead(long)
メソッドで使用できるスタンプを返します。 時間指定のないバージョンと時間指定のあるバージョンのtryReadLock
も用意されています。 - オプティミスティック読取り。
tryOptimisticRead()
メソッドは、現在ロックが書込みモードで保持されていない場合のみ、ゼロ以外のスタンプを返します。 メソッドvalidate(long)
は、指定のスタンプが取得されてからロックが書込みモードで取得されなかった場合にtrueを返します。この場合、tryOptimisticRead
への呼び出しのあとに、最新の書き込みロック・リリースより前のすべてのアクションが発生します。 このモードは、ライターがいつでも破ることのできる、きわめて弱い読取りロックと見なすことができます。 短い読取り専用コード・セグメントにはオプティミスティック読取りモードを使用することで、競合が減少し、スループットが向上することがよくあります。 ただし、その使用は本質的に脆弱です。 オプティミスティック読取りセクションでは、フィールドを読み取り、それらを後で検証してから使用するためにローカル変数に保持することだけを行うべきです。 オプティミスティック読取りモードでは読取りフィールドに一貫性がない場合があるため、データ表現を十分に理解していて一貫性をチェックしたり、メソッドvalidate()
を繰り返し呼び出す場合にのみ使用方法が適用されます。 たとえば、最初にオブジェクト参照または配列参照を読み取り、次にそのフィールド、要素、またはメソッドの1つにアクセスする場合、通常そのような手順が必要になります。
このクラスは、条件に応じて3つのモード間の変換を提供するメソッドもサポートしています。 たとえば、メソッド
tryConvertToWriteLock(long)
は、モード"upgrade"への試みを行い、(1)がすでに書込みモード(2)の読取りモードである場合に有効な書込みスタンプを返します。さらに、オプティミスティック読取りモードでは、他のリーダーまたは(3)は存在せず、ロックは使用できます。 これらのメソッドの形式は、再試行ベースの設計で発生するコードの膨張をいくから軽減できるように設計されています。StampedLockは、スレッドセーフなコンポーネントの開発で内部ユーティリティとして使用するために設計されています。 これらを使用するには、保護するデータ、オブジェクト、およびメソッドの内部プロパティの知識が必要です。 これらは再入可能ではないため、ロックされている本体では、ロックの再取得を試みる可能性のある他の不明なメソッドを呼び出すべきではありません(ただし、スタンプを使用または変換できる他のメソッドにスタンプを渡すことはできます)。 読取りロック・モードを使用するには、関連するコード・セクションが副作用を持っていないことが必要です。 未検証のオプティミスティック読取りセクションでは、潜在的な不整合を許容できることがわかっていないメソッドを呼び出すことはできません。 スタンプは有限表示を使用し、暗号的にセキュアではありません(つまり、有効なスタンプが推測可能な場合があります)。 スタンプの値は、1年以上の連続動作の後で再循環する場合があります。 これより長い期間、使用も検証もされずに保持されたスタンプは、正しく検証できない場合があります。 StampedLockは直列化可能ですが、常に初期のロック解除された状態に直列化復元されるため、リモート・ロックには役立ちません。
Semaphore
のように、ほとんどのLock
実装とは異なり、StampedLocksには所有権の概念はありません。 あるスレッドで取得されたロックは、別のスレッドで解放または変換できます。StampedLockのスケジューリング・ポリシーでは、リーダーとライターのどちらを優先するかに一貫性がありません。 tryメソッドはすべてベスト・エフォート型であり、スケジューリング・ポリシーや公平性ポリシーに必ずしも準拠していません。 ロックを取得または変換するtryメソッドからゼロが返された場合、ロックの状態に関する情報は提供されません。それ以降の呼び出しが成功する場合もあります。
このクラスでは、複数のロック・モードを調整する使用方法がサポートされているため、
Lock
インタフェースやReadWriteLock
インタフェースは直接実装されません。 ただし、関連する機能セットだけを必要とするアプリケーションでは、StampedLockがasReadLock()
、asWriteLock()
、またはasReadWriteLock()
と見なされることもあります。メモリーの同期化 どのモードでも正常にロックされたことが原因で、メモリー同期の効果は、「第17章of Java™言語仕様」で説明されている「ロック」アクションと同じです。 書込みモードでメソッドのロックを正常に解除すると、メモリー同期の結果は「ロック解除」アクションと同じになります。 オプティミスティック読取りの使用方法では、最新の書込みモードのロック解除アクションより前のアクションは、将来の検証でtrueが戻された場合にのみ、tryOptimisticReadの後続のアクションが発生することが保証されています。そうでない場合、tryOptimisticRead間の読取りと一貫性のあるスナップショットの取得は保証されません。
使用例。 単純な2次元の点を保持するクラスにおけるいくつかの使用方法を次に示します。 サンプル・コードにはいくつかのtry/catch技法が示されていますが、その本体で例外が発生する可能性はないため、ここではこれらが厳密に必要なわけではありません。
class Point { private double x, y; private final StampedLock sl = new StampedLock(); // an exclusively locked method void move(double deltaX, double deltaY) { long stamp = sl.writeLock(); try { x += deltaX; y += deltaY; } finally { sl.unlockWrite(stamp); } } // a read-only method // upgrade from optimistic read to read lock double distanceFromOrigin() { long stamp = sl.tryOptimisticRead(); try { retryHoldingLock: for (;; stamp = sl.readLock()) { if (stamp == 0L) continue retryHoldingLock; // possibly racy reads double currentX = x; double currentY = y; if (!sl.validate(stamp)) continue retryHoldingLock; return Math.hypot(currentX, currentY); } } finally { if (StampedLock.isReadLockStamp(stamp)) sl.unlockRead(stamp); } } // upgrade from optimistic read to write lock void moveIfAtOrigin(double newX, double newY) { long stamp = sl.tryOptimisticRead(); try { retryHoldingLock: for (;; stamp = sl.writeLock()) { if (stamp == 0L) continue retryHoldingLock; // possibly racy reads double currentX = x; double currentY = y; if (!sl.validate(stamp)) continue retryHoldingLock; if (currentX != 0.0 || currentY != 0.0) break; stamp = sl.tryConvertToWriteLock(stamp); if (stamp == 0L) continue retryHoldingLock; // exclusive access x = newX; y = newY; return; } } finally { if (StampedLock.isWriteLockStamp(stamp)) sl.unlockWrite(stamp); } } // Upgrade read lock to write lock void moveIfAtOrigin(double newX, double newY) { long stamp = sl.readLock(); try { while (x == 0.0 && y == 0.0) { long ws = sl.tryConvertToWriteLock(stamp); if (ws != 0L) { stamp = ws; x = newX; y = newY; break; } else { sl.unlockRead(stamp); stamp = sl.writeLock(); } } } finally { sl.unlock(stamp); } } }
- 導入されたバージョン:
- 1.8
- 関連項目:
- 直列化された形式
-
-
コンストラクタのサマリー
コンストラクタ コンストラクタ 説明 StampedLock()
新しいロックを、最初はロック解除された状態で作成します。
-
メソッドのサマリー
修飾子と型 メソッド 説明 Lock
asReadLock()
このStampedLockのプレーンなLock
ビューを返します。そこでは、Lock.lock()
メソッドがreadLock()
にマップされ、他のメソッドも同様にマップされます。ReadWriteLock
asReadWriteLock()
このStampedLockのReadWriteLock
ビューを返します。そこでは、ReadWriteLock.readLock()
メソッドがasReadLock()
にマップされ、ReadWriteLock.writeLock()
がasWriteLock()
にマップされます。Lock
asWriteLock()
このStampedLockのプレーンなLock
ビューを返します。そこでは、Lock.lock()
メソッドがwriteLock()
にマップされ、他のメソッドも同様にマップされます。int
getReadLockCount()
このロック用に保持されている読込みロックの数を照会します。static boolean
isLockStamp(long stamp)
スタンプがロックを保持しているかどうかを示します。static boolean
isOptimisticReadStamp(long stamp)
スタンプが楽観的な読書が成功したかどうかを示します。boolean
isReadLocked()
現在ロックが非排他的に保持されている場合はtrue
を返します。static boolean
isReadLockStamp(long stamp)
スタンプが非排他的にロックを保持しているかどうかを示します。boolean
isWriteLocked()
現在ロックが排他的に保持されている場合はtrue
を返します。static boolean
isWriteLockStamp(long stamp)
スタンプが排他的にロックを保持しているかどうかを示します。long
readLock()
ロックを非排他的に取得し、利用可能になるまで必要に応じてブロックします。long
readLockInterruptibly()
ロックを非排他的に取得し、利用可能になるまで、または現在のスレッドが割り込まれるまで、必要に応じてブロックします。String
toString()
このロックおよびその状態を識別する文字列を返します。long
tryConvertToOptimisticRead(long stamp)
ロック状態が指定されたスタンプと一致する場合、原子的に、スタンプがロックを保持していることを表す場合は、それを解放して観測スタンプを返します。long
tryConvertToReadLock(long stamp)
ロック状態が指定されたスタンプと一致する場合、以下のアクションのいずれかを原子的に実行します。long
tryConvertToWriteLock(long stamp)
ロック状態が指定されたスタンプと一致する場合、以下のアクションのいずれかを原子的に実行します。long
tryOptimisticRead()
後で検証できるスタンプを返します。排他的にロックされている場合はゼロを返します。long
tryReadLock()
ロックがすぐに利用できる場合に、それを非排他的に取得します。long
tryReadLock(long time, TimeUnit unit)
指定された時間内でロックが利用可能になり、現在のスレッドで割込みが発生していない場合に、それを非排他的に取得します。boolean
tryUnlockRead()
読取りロックが保持される場合に、スタンプ値を必要としないで、その保持を解除します。boolean
tryUnlockWrite()
書込みロックが保持される場合に、スタンプ値を必要としないで、それを解除します。long
tryWriteLock()
ロックがすぐに利用できる場合に、それを排他的に取得します。long
tryWriteLock(long time, TimeUnit unit)
指定された時間内でロックが利用可能になり、現在のスレッドで割込みが発生していない場合に、それを排他的に取得します。void
unlock(long stamp)
ロック状態が指定されたスタンプと一致する場合に、対応するロック・モードを解除します。void
unlockRead(long stamp)
ロック状態が指定されたスタンプと一致する場合に、非排他ロックを解除します。void
unlockWrite(long stamp)
ロック状態が指定されたスタンプと一致する場合に、排他ロックを解除します。boolean
validate(long stamp)
指定されたスタンプの発行以降にロックが排他的に取得されなかった場合にtrueを返します。long
writeLock()
ロックを排他的に取得し、必要に応じて利用可能になるまでブロックします。long
writeLockInterruptibly()
ロックを排他的に取得し、必要に応じて利用可能になるか、現在のスレッドで割込みが発生するまでブロックします。
-
-
-
メソッドの詳細
-
writeLock
public long writeLock()
ロックを排他的に取得し、必要に応じて利用可能になるまでブロックします。- 戻り値:
- モードを解除または変換するために使用できる書き込みスタンプ
-
tryWriteLock
public long tryWriteLock()
ロックがすぐに利用できる場合に、それを排他的に取得します。- 戻り値:
- ロック解除または変換モードに使用できる書き込みスタンプ、またはロックが使用できない場合はゼロ
-
tryWriteLock
public long tryWriteLock(long time, TimeUnit unit) throws InterruptedException
指定された時間内でロックが利用可能になり、現在のスレッドで割込みが発生していない場合に、それを排他的に取得します。 タイムアウト時および割込み時の動作は、Lock.tryLock(long,TimeUnit)
メソッドに指定されているものと同じです。- パラメータ:
time
- ロックの最長待機時間unit
-time
引数の時間単位- 戻り値:
- ロック解除または変換モードに使用できる書き込みスタンプ、またはロックが使用できない場合はゼロ
- 例外:
InterruptedException
- ロックを取得する前に現在のスレッドで割込みが発生した場合
-
writeLockInterruptibly
public long writeLockInterruptibly() throws InterruptedException
ロックを排他的に取得し、必要に応じて利用可能になるか、現在のスレッドで割込みが発生するまでブロックします。 割込み時の動作は、Lock.lockInterruptibly()
メソッドに指定されているものと同じです。- 戻り値:
- モードを解除または変換するために使用できる書き込みスタンプ
- 例外:
InterruptedException
- ロックを取得する前に現在のスレッドで割込みが発生した場合
-
readLock
public long readLock()
ロックを非排他的に取得し、利用可能になるまで必要に応じてブロックします。- 戻り値:
- モードを解除または変換するために使用できる読み取りスタンプ
-
tryReadLock
public long tryReadLock()
ロックがすぐに利用できる場合に、それを非排他的に取得します。- 戻り値:
- モードのロック解除または変換に使用できる読み取りスタンプ、またはロックが使用できない場合はゼロ
-
tryReadLock
public long tryReadLock(long time, TimeUnit unit) throws InterruptedException
指定された時間内でロックが利用可能になり、現在のスレッドで割込みが発生していない場合に、それを非排他的に取得します。 タイムアウト時および割込み時の動作は、Lock.tryLock(long,TimeUnit)
メソッドに指定されているものと同じです。- パラメータ:
time
- ロックの最長待機時間unit
-time
引数の時間単位- 戻り値:
- モードのロック解除または変換に使用できる読み取りスタンプ、またはロックが使用できない場合はゼロ
- 例外:
InterruptedException
- ロックを取得する前に現在のスレッドで割込みが発生した場合
-
readLockInterruptibly
public long readLockInterruptibly() throws InterruptedException
ロックを非排他的に取得し、利用可能になるまで、または現在のスレッドが割り込まれるまで、必要に応じてブロックします。 割込み時の動作は、Lock.lockInterruptibly()
メソッドに指定されているものと同じです。- 戻り値:
- モードを解除または変換するために使用できる読み取りスタンプ
- 例外:
InterruptedException
- ロックを取得する前に現在のスレッドで割込みが発生した場合
-
tryOptimisticRead
public long tryOptimisticRead()
後で検証できるスタンプを返します。排他的にロックされている場合はゼロを返します。- 戻り値:
- 有効な楽観的な読み取りスタンプ、または排他的にロックされている場合はゼロ
-
validate
public boolean validate(long stamp)
指定されたスタンプの発行以降にロックが排他的に取得されなかった場合にtrueを返します。 スタンプがゼロの場合は常にfalseを返します。 スタンプが現在保持されているロックを表している場合は、常にtrueを返します。tryOptimisticRead()
またはこのロックのロック・メソッドから取得されたものではない値を指定してこのメソッドを呼び出した場合、その効果や結果は定義されていません。- パラメータ:
stamp
- スタンプ- 戻り値:
- 指定されたスタンプの発行以降にロックが排他的に取得されていない場合は
true
、それ以外の場合はfalse
-
unlockWrite
public void unlockWrite(long stamp)
ロック状態が指定されたスタンプと一致する場合に、排他ロックを解除します。- パラメータ:
stamp
- 書込みロック操作によって返されたスタンプ- 例外:
IllegalMonitorStateException
- スタンプがこのロックの現在の状態と一致しない場合
-
unlockRead
public void unlockRead(long stamp)
ロック状態が指定されたスタンプと一致する場合に、非排他ロックを解除します。- パラメータ:
stamp
- 読取りロック操作によって返されたスタンプ- 例外:
IllegalMonitorStateException
- スタンプがこのロックの現在の状態と一致しない場合
-
unlock
public void unlock(long stamp)
ロック状態が指定されたスタンプと一致する場合に、対応するロック・モードを解除します。- パラメータ:
stamp
- ロック操作によって返されたスタンプ- 例外:
IllegalMonitorStateException
- スタンプがこのロックの現在の状態と一致しない場合
-
tryConvertToWriteLock
public long tryConvertToWriteLock(long stamp)
ロック状態が指定されたスタンプと一致する場合、以下のアクションのいずれかを原子的に実行します。 スタンプが書込みロックの保持を表している場合は、それを返します。 読取りロックであれば、書込みロックが使用可能な場合は読取りロックを解放し、書込みスタンプを返します。 オプティミスティック読取りであれば、すぐに利用できる場合のみ書込みスタンプを返します。 このメソッドは、その他の場合はすべてゼロを返します。- パラメータ:
stamp
- スタンプ- 戻り値:
- 有効な書込みスタンプ。失敗した場合はゼロ
-
tryConvertToReadLock
public long tryConvertToReadLock(long stamp)
ロック状態が指定されたスタンプと一致する場合、以下のアクションのいずれかを原子的に実行します。 スタンプが書込みロックの保持を表している場合は、それを解放し、読取りロックを取得します。 読取りロックであれば、それを返します。 オプティミスティック読取りであれば、すぐに利用できる場合のみ読取りロックを取得し、読取りスタンプを返します。 このメソッドは、その他の場合はすべてゼロを返します。- パラメータ:
stamp
- スタンプ- 戻り値:
- 有効な読取りスタンプ。失敗した場合はゼロ
-
tryConvertToOptimisticRead
public long tryConvertToOptimisticRead(long stamp)
ロック状態が指定されたスタンプと一致する場合、原子的に、スタンプがロックを保持していることを表す場合は、それを解放して観測スタンプを返します。 オプティミスティック読取りであれば、検証されている場合はそれを返します。 このメソッドは、その他の場合はすべてゼロを返すため、tryUnlockの一種として役立つ場合があります。- パラメータ:
stamp
- スタンプ- 戻り値:
- 有効なオプティミスティック読取りスタンプ。失敗した場合はゼロ
-
tryUnlockWrite
public boolean tryUnlockWrite()
書込みロックが保持される場合に、スタンプ値を必要としないで、それを解除します。 このメソッドは、エラー後の回復に役立つ場合があります。- 戻り値:
- ロックが保持されていた場合は
true
。それ以外の場合はfalse
-
tryUnlockRead
public boolean tryUnlockRead()
読取りロックが保持される場合に、スタンプ値を必要としないで、その保持を解除します。 このメソッドは、エラー後の回復に役立つ場合があります。- 戻り値:
- 読取りロックが保持されていた場合は
true
。それ以外の場合はfalse
-
isWriteLocked
public boolean isWriteLocked()
現在ロックが排他的に保持されている場合はtrue
を返します。- 戻り値:
- 現在ロックが排他的に保持されている場合は
true
-
isReadLocked
public boolean isReadLocked()
現在ロックが非排他的に保持されている場合はtrue
を返します。- 戻り値:
- 現在ロックが非排他的に保持されている場合は
true
-
isWriteLockStamp
public static boolean isWriteLockStamp(long stamp)
スタンプが排他的にロックを保持しているかどうかを示します。 このメソッドは、tryConvertToWriteLock(long)
と組み合わせて使用すると便利です。例:long stamp = sl.tryOptimisticRead(); try { ... stamp = sl.tryConvertToWriteLock(stamp); ... } finally { if (StampedLock.isWriteLockStamp(stamp)) sl.unlockWrite(stamp); }
- パラメータ:
stamp
- 以前のStampedLock操作によって返されたスタンプ- 戻り値:
true
スタンプが正常な書き込みロック操作によって戻された場合- 導入されたバージョン:
- 10
-
isReadLockStamp
public static boolean isReadLockStamp(long stamp)
スタンプが非排他的にロックを保持しているかどうかを示します。 このメソッドは、tryConvertToReadLock(long)
と組み合わせて使用すると便利です。例:long stamp = sl.tryOptimisticRead(); try { ... stamp = sl.tryConvertToReadLock(stamp); ... } finally { if (StampedLock.isReadLockStamp(stamp)) sl.unlockRead(stamp); }
- パラメータ:
stamp
- 以前のStampedLock操作によって返されたスタンプ- 戻り値:
- 成功した読み取りロック操作によってスタンプが戻された場合は
true
- 導入されたバージョン:
- 10
-
isLockStamp
public static boolean isLockStamp(long stamp)
スタンプがロックを保持しているかどうかを示します。 このメソッドは、tryConvertToReadLock(long)
およびtryConvertToWriteLock(long)
と一緒に使用すると便利です。たとえば、次のようになります:long stamp = sl.tryOptimisticRead(); try { ... stamp = sl.tryConvertToReadLock(stamp); ... stamp = sl.tryConvertToWriteLock(stamp); ... } finally { if (StampedLock.isLockStamp(stamp)) sl.unlock(stamp); }
- パラメータ:
stamp
- 以前のStampedLock操作によって返されたスタンプ- 戻り値:
- 成功した読み取りロックまたは書き込みロック操作によってスタンプが戻された場合は
true
- 導入されたバージョン:
- 10
-
isOptimisticReadStamp
public static boolean isOptimisticReadStamp(long stamp)
スタンプが楽観的な読書が成功したかどうかを示します。- パラメータ:
stamp
- 以前のStampedLock操作によって返されたスタンプ- 戻り値:
true
tryOptimisticRead()
またはtryConvertToOptimisticRead(long)
からの非ゼロ戻りの正常な読み取り操作によってスタンプが戻された場合- 導入されたバージョン:
- 10
-
getReadLockCount
public int getReadLockCount()
このロック用に保持されている読込みロックの数を照会します。 このメソッドは、同期の制御用としてではなく、システム状態の監視用として設計されています。- 戻り値:
- 保持する読込みロックの数
-
toString
public String toString()
このロックおよびその状態を識別する文字列を返します。 状態は括弧で囲まれ、文字列"Unlocked"
または文字列"Write-locked"
または文字列"Read-locks:"
に続いて、現在保持されている読取りロックの数が含まれます。
-
asReadLock
public Lock asReadLock()
このStampedLockのプレーンなLock
ビューを返します。そこでは、Lock.lock()
メソッドがreadLock()
にマップされ、他のメソッドも同様にマップされます。 返されたLockはCondition
をサポートしていないため、Lock.newCondition()
メソッドはUnsupportedOperationException
をスローします。- 戻り値:
- ロック
-
asWriteLock
public Lock asWriteLock()
このStampedLockのプレーンなLock
ビューを返します。そこでは、Lock.lock()
メソッドがwriteLock()
にマップされ、他のメソッドも同様にマップされます。 返されたLockはCondition
をサポートしていないため、Lock.newCondition()
メソッドはUnsupportedOperationException
をスローします。- 戻り値:
- ロック
-
asReadWriteLock
public ReadWriteLock asReadWriteLock()
このStampedLockのReadWriteLock
ビューを返します。そこでは、ReadWriteLock.readLock()
メソッドがasReadLock()
にマップされ、ReadWriteLock.writeLock()
がasWriteLock()
にマップされます。- 戻り値:
- ロック
-
-