モジュール java.base

クラスReentrantReadWriteLock

java.lang.Object
java.util.concurrent.locks.ReentrantReadWriteLock
すべての実装されたインタフェース:
Serializable, ReadWriteLock

public class ReentrantReadWriteLock extends Object implements ReadWriteLock, Serializable
ReentrantLockと同様のセマンティックスをサポートするReadWriteLockの実装です。

このクラスには次の特性があります。

  • 取得順序

    このクラスは、ロック・アクセスに対するリーダーまたはライターの優先順序を規定しません。 ただし、オプションの公平性ポリシーをサポートします。

    不公平モード(デフォルト)
    不公平として構築された場合は(デフォルト)、読み込みおよび書込みロックに入る順序は指定されず、再入可能性制約に従います。 継続的に競合していた不公平ロックでは、1つ以上のリーダーまたはライター・スレッドを無期限に延期することがありますが、通常は公平ロックよりスループットが高くなります。
    公平モード
    公平として構築された場合、スレッドは近似の到着順ポリシーを使用してエントリで競合します。 現在保持されているロックが解放されると、待機時間のもっとも長い単一のライター・スレッドに書込みロックが割り当てられるか、待機中のどのライター・スレッドよりも長く待機しているリーダー・スレッドのグループが存在する場合は、そのグループに読込みロックが割り当てられます。

    書込みロックが保持されている場合や待機中のライター・スレッドが存在する場合、公平読込みロック(再入不可能)を取得しようとするスレッドはブロックされます。 そのようなスレッドは、現在待機中のライター・スレッドのうちもっとも古いスレッドが書込みロックを取得して解放するまで、読込みロックを取得しません。 もちろん、待機中のライターが待機を中止し、キュー内でもっとも長く待機している1つ以上のリーダー・スレッドに書込みロックがかかっていない場合は、それらのリーダーに読込みロックが割り当てられます。

    読込みロックも書込みロックもかかっていない(つまり待機中のスレッドがない)場合を除き、公平書込みロック(再入不可能)を取得しようとするスレッドはブロックされます。 (非ブロックのReentrantReadWriteLock.ReadLock.tryLock()メソッドとReentrantReadWriteLock.WriteLock.tryLock()メソッドはこの公平設定に従わず、待機中のスレッドには関係なく、可能であればロックをただちに取得することに注意してください。)

  • 再入可能性

    このロックにより、リーダーとライターの両方が、ReentrantLockのスタイルで読み取りまたは書込みロックを再取得できるようになります。 書き込むスレッドの保持する書込みロックがすべて解放されるまで、再入不可能なリーダーは許可されません。

    また、ライターは読込みロックを取得できますが、リーダーが書込みロックを取得することはできません。 ほかのアプリケーションの間では、読込みロック下で読込みを実行するメソッドへの呼び出しまたはコールバック中に書込みロックが保持される場合、再入可能性は有用です。 リーダーが書込みロックを取得しようとしても、成功しません。

  • ロックの降格

    再入可能性を利用すると、書込みロックを取得してから読込みロックを取得し、その後書込みロックを解放するという方法で、書込みロックから読込みロックへの降格が可能になります。 ただし、読込みロックから書込みロックへの昇格はできません

  • ロック取得の割り込み

    読込みロックと書込みロックの両方が、ロック取得中の割込みをサポートします。

  • Conditionのサポート

    書込みロックの提供するCondition実装は、書込みロックに関して、ReentrantLock.newCondition()によって提供されるCondition実装がReentrantLockに対して実行するのと同じように動作します。 このConditionは当然、書込みロックでのみ使用できます。

    読込みロックはConditionをサポートしていないため、readLock().newCondition()UnsupportedOperationExceptionをスローします。

  • インストゥルメンテーション

    このクラスは、ロックが保持されるか競合するかを判別するメソッドをサポートします。 これらのメソッドは、同期の制御用としてではなく、システム状態の監視用として設計されています。

このクラスの直列化は、組込みロックと同様に動作します。直列化解除されたロックは、直列化時の状態にかかわらず、ロック解除状態になります。

使用例 次のコード例では、キャッシュを更新したあとにロックの降格を実行する方法を示します(入れ子を使用しない方法で複数のロックを処理する場合の例外処理は特に注意が必要)。

 
 class CachedData {
   Object data;
   boolean cacheValid;
   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

   void processCachedData() {
     rwl.readLock().lock();
     if (!cacheValid) {
       // Must release read lock before acquiring write lock
       rwl.readLock().unlock();
       rwl.writeLock().lock();
       try {
         // Recheck state because another thread might have
         // acquired write lock and changed state before we did.
         if (!cacheValid) {
           data = ...;
           cacheValid = true;
         }
         // Downgrade by acquiring read lock before releasing write lock
         rwl.readLock().lock();
       } finally {
         rwl.writeLock().unlock(); // Unlock write, still hold read
       }
     }

     try {
       use(data);
     } finally {
       rwl.readLock().unlock();
     }
   }
 }
ReentrantReadWriteLocksを使用して、ある種のCollectionsの使用で並行性を改善できます。 通常、これが価値があるのは、コレクションが大規模になることが予想され、ライター・スレッドよりも多数のリーダー・スレッドによりアクセスされ、同期によるオーバーヘッドを上回るオーバーヘッドを持つ操作が含まれる場合です。 たとえば、大規模で、並行アクセスが予想されるTreeMapを使用するクラスを次に示します。
 
 class RWDictionary {
   private final Map<String, Data> m = new TreeMap<>();
   private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
   private final Lock r = rwl.readLock();
   private final Lock w = rwl.writeLock();

   public Data get(String key) {
     r.lock();
     try { return m.get(key); }
     finally { r.unlock(); }
   }
   public List<String> allKeys() {
     r.lock();
     try { return new ArrayList<>(m.keySet()); }
     finally { r.unlock(); }
   }
   public Data put(String key, Data value) {
     w.lock();
     try { return m.put(key, value); }
     finally { w.unlock(); }
   }
   public void clear() {
     w.lock();
     try { m.clear(); }
     finally { w.unlock(); }
   }
 }

実装ノート

このロックは、最大65535の再帰的書込みロックおよび65535の読込みロックをサポートします。 これらの制限を超えようとすると、ロックしているメソッドからErrorがスローされます。

導入されたバージョン:
1.5
関連項目: