モジュール java.base

クラスStampedLock

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()と見なされることもあります。

メモリーの同期化 正常にロックされた場合のいずれかのモードへの影響を及ぼすメソッドのメモリー同期は、「Java™言語仕様」の第17章 で説明しているように、「ロック」アクションと同じ効果を持ちます。 書込みモードでメソッドのロックを正常に解除すると、メモリー同期の結果は「ロック解除」アクションと同じになります。 オプティミスティック読取りの使用方法では、最新の書込みモードのロック解除アクションより前のアクションは、将来の検証で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);
     }
   }
 }

Java言語仕様を参照してください:
17.4 メモリー・モデル
導入されたバージョン:
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()
    ロックを排他的に取得し、必要に応じて利用可能になるか、現在のスレッドで割込みが発生するまでブロックします。

    クラス java.lang.Objectで宣言されたメソッド

    cloneequalsfinalizegetClasshashCodenotifynotifyAllwaitwaitwait
  • コンストラクタの詳細

    • StampedLock

      public StampedLock()
      新しいロックを、最初はロック解除された状態で作成します。
  • メソッドの詳細

    • 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:"に続いて、現在保持されている読取りロックの数が含まれます。
      オーバーライド:
      toString 、クラス:  Object
      戻り値:
      このロックおよびその状態を識別する文字列
    • 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()にマップされます。
      戻り値:
      ロック