Module java.base

Class ReentrantReadWriteLock

java.lang.Object
java.util.concurrent.locks.ReentrantReadWriteLock
所有已实现的接口:
Serializable, ReadWriteLock

public class ReentrantReadWriteLock extends Object implements ReadWriteLock, Serializable
支持类似于ReentrantLock的语义的ReadWriteLock的实现。

此类具有以下属性:

  • 获取顺序

    此类不对锁访问施加读者或写者优先顺序。但是,它支持一个可选的公平性策略。

    非公平模式(默认)
    当构造为非公平(默认)时,对读锁和写锁的进入顺序是未指定的,受到重入约束的限制。一个连续争用的非公平锁可能会无限期地推迟一个或多个读者或写者线程,但通常比公平锁具有更高的吞吐量。
    公平模式
    当构造为公平时,线程根据近似到达顺序策略争夺进入。当当前持有的锁被释放时,要么最长等待的单个写线程将被分配写锁,要么如果有一组读线程等待时间比所有等待的写线程都长,那么该组将被分配读锁。

    尝试获取公平读锁(非可重入地)的线程将在写锁被持有或有等待的写线程时阻塞。该线程直到最老的当前等待的写线程已经获取并释放写锁后才会获取读锁。当然,如果一个等待的写线程放弃等待,留下一个或多个读线程作为队列中持有写锁的最长等待者,那么这些读者将被分配读锁。

    尝试获取公平写锁(非可重入地)的线程将阻塞,除非读锁和写锁都是空闲的(这意味着没有等待的线程)。(请注意,非阻塞的ReentrantReadWriteLock.ReadLock.tryLock()ReentrantReadWriteLock.WriteLock.tryLock()方法不遵守此公平设置,如果可能的话将立即获取锁,而不考虑等待的线程。)

  • 可重入性

    此锁允许读者和写者以ReentrantLock的方式重新获取读锁或写锁。在写线程持有的所有写锁都已释放之前,不允许非可重入的读者。

    此外,写者可以获取读锁,但反之则不行。在其他应用中,当在执行读锁下的方法或回调时持有写锁时,可重入性可能很有用。如果读者尝试获取写锁,它将永远不会成功。

  • 锁降级

    可重入性还允许从写锁降级到读锁,方法是先获取写锁,然后获取读锁,最后释放写锁。但是,从读锁升级到写锁是可能的。

  • 锁获取中断

    读锁和写锁都支持在锁获取期间的中断。

  • Condition支持

    写锁提供了一个与ReentrantLock.newCondition()ReentrantLock提供的Condition实现相同的行为的Condition实现。当然,这个Condition只能与写锁一起使用。

    读锁不支持ConditionreadLock().newCondition()会抛出UnsupportedOperationException

  • 仪器化

    此类支持用于确定锁是否被持有或争用的方法。这些方法设计用于监视系统状态,而不是用于同步控制。

此类的序列化行为与内置锁相同:反序列化的锁处于未锁定状态,而不管序列化时的状态如何。

示例用法。以下是一个代码草图,显示如何在更新缓存后执行锁降级(在非嵌套方式处理多个锁时,异常处理特别棘手):

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

   void processCachedData() {
     rwl.readLock().lock();
     if (!cacheValid) {
       // 必须在获取写锁之前释放读锁
       rwl.readLock().unlock();
       rwl.writeLock().lock();
       try {
         // 重新检查状态,因为另一个线程可能在我们之前获取写锁并更改状态。
         if (!cacheValid) {
           data = ...;
           cacheValid = true;
         }
         // 通过在释放写锁之前获取读锁来降级
         rwl.readLock().lock();
       } finally {
         rwl.writeLock().unlock(); // 释放写锁,仍然持有读锁
       }
     }

     try {
       use(data);
     } finally {
       rwl.readLock().unlock();
     }
   }
 }
ReentrantReadWriteLock可以用于改进某些类型的集合的并发性。这通常只有在预计集合将很大,被更多读线程访问而不是写线程,并且涉及的操作的开销超过同步开销时才值得。例如,以下是一个使用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
参见:
  • Constructor Details

    • ReentrantReadWriteLock

      public ReentrantReadWriteLock()
      使用默认(非公平)排序属性创建一个新的ReentrantReadWriteLock
    • ReentrantReadWriteLock

      public ReentrantReadWriteLock(boolean fair)
      使用给定的公平性策略创建一个新的ReentrantReadWriteLock
      参数:
      fair - 如果此锁应使用公平排序策略,则为true
  • Method Details

    • writeLock

      public ReentrantReadWriteLock.WriteLock writeLock()
      从接口复制的描述: ReadWriteLock
      返回用于写入的锁。
      指定者:
      writeLock 在接口 ReadWriteLock
      返回:
      用于写入的锁
    • readLock

      public ReentrantReadWriteLock.ReadLock readLock()
      从接口复制的描述: ReadWriteLock
      返回用于读取的锁。
      指定者:
      readLock 在接口 ReadWriteLock
      返回值:
      用于读取的锁
    • isFair

      public final boolean isFair()
      如果此锁设置为公平,则返回true
      返回值:
      如果此锁设置为公平,则返回true
    • getOwner

      protected Thread getOwner()
      返回当前拥有写锁的线程,如果未拥有则返回null。当非所有者线程调用此方法时,返回值反映当前锁状态的最佳估计。例如,即使有线程尝试获取锁但尚未成功,所有者可能暂时为null。此方法旨在便于构建提供更广泛锁监控功能的子类。
      返回值:
      所有者,如果未拥有则为null
    • getReadLockCount

      public int getReadLockCount()
      查询持有此锁的读取锁数量。此方法设计用于监控系统状态,而非同步控制。
      返回值:
      持有的读取锁数量
    • isWriteLocked

      public boolean isWriteLocked()
      查询写锁是否由任何线程持有。此方法设计用于监控系统状态,而非同步控制。
      返回值:
      如果有任何线程持有写锁则返回true,否则返回false
    • isWriteLockedByCurrentThread

      public boolean isWriteLockedByCurrentThread()
      查询当前线程是否持有写锁。
      返回值:
      如果当前线程持有写锁则返回true,否则返回false
    • getWriteHoldCount

      public int getWriteHoldCount()
      查询当前线程对此锁的可重入写持有数。写线程对于每个未匹配的解锁操作都会对锁保持一次持有。
      返回值:
      当前线程对写锁的持有数,如果当前线程未持有写锁则返回零
    • getReadHoldCount

      public int getReadHoldCount()
      查询当前线程对此锁的可重入读持有数。读线程对于每个未匹配的解锁操作都会对锁保持一次持有。
      返回值:
      当前线程对读锁的持有数,如果当前线程未持有读锁则返回零
      自JDK版本:
      1.6
    • getQueuedWriterThreads

      protected Collection<Thread> getQueuedWriterThreads()
      返回包含可能正在等待获取写锁的线程的集合。由于在构建此结果时实际线程集可能动态变化,因此返回的集合仅是最佳估计。返回集合的元素没有特定顺序。此方法旨在便于构建提供更广泛锁监控功能的子类。
      返回值:
      线程集合
    • getQueuedReaderThreads

      protected Collection<Thread> getQueuedReaderThreads()
      返回包含可能正在等待获取读锁的线程的集合。由于在构建此结果时实际线程集可能动态变化,因此返回的集合仅是最佳估计。返回集合的元素没有特定顺序。此方法旨在便于构建提供更广泛锁监控功能的子类。
      返回值:
      线程集合
    • hasQueuedThreads

      public final boolean hasQueuedThreads()
      查询是否有任何线程正在等待获取读取或写入锁。请注意,由于随时可能发生取消,返回true并不保证任何其他线程将来会获取锁。此方法主要用于监控系统状态。
      返回值:
      如果可能有其他线程正在等待获取锁,则返回true
    • hasQueuedThread

      public final boolean hasQueuedThread(Thread thread)
      查询给定线程是否正在等待获取读取或写入锁。请注意,由于随时可能发生取消,返回true并不保证此线程将来会获取锁。此方法主要用于监控系统状态。
      参数:
      thread - 线程
      返回值:
      如果给定线程在排队等待此锁,则返回true
      抛出:
      NullPointerException - 如果线程为null
    • getQueueLength

      public final int getQueueLength()
      返回等待获取读取或写入锁的线程数的估计值。该值仅是一个估计,因为在此方法遍历内部数据结构时,线程数可能会动态变化。此方法设计用于监控系统状态,而非同步控制。
      返回值:
      等待此锁的线程数的估计值
    • getQueuedThreads

      protected Collection<Thread> getQueuedThreads()
      返回包含可能正在等待获取读取或写入锁的线程的集合。由于在构建此结果时实际线程集可能动态变化,因此返回的集合仅是最佳估计。返回集合的元素没有特定顺序。此方法旨在便于构建提供更广泛监控功能的子类。
      返回值:
      线程集合
    • hasWaiters

      public boolean hasWaiters(Condition condition)
      查询是否有任何线程正在等待与写入锁关联的给定条件。请注意,由于随时可能发生超时和中断,返回true并不保证将来的signal会唤醒任何线程。此方法主要用于监控系统状态。
      参数:
      condition - 条件
      返回值:
      如果有任何等待线程则返回true
      抛出:
      IllegalMonitorStateException - 如果未持有此锁
      IllegalArgumentException - 如果给定条件与此锁不相关
      NullPointerException - 如果条件为null
    • getWaitQueueLength

      public int getWaitQueueLength(Condition condition)
      返回等待与写入锁关联的给定条件的线程数的估计值。请注意,由于随时可能发生超时和中断,该估计仅作为实际等待者数量的上限。此方法设计用于监控系统状态,而非同步控制。
      参数:
      condition - 条件
      返回值:
      等待线程数的估计值
      抛出:
      IllegalMonitorStateException - 如果未持有此锁
      IllegalArgumentException - 如果给定条件与此锁不相关
      NullPointerException - 如果条件为null
    • getWaitingThreads

      protected Collection<Thread> getWaitingThreads(Condition condition)
      返回包含可能正在等待与写入锁关联的给定条件的线程的集合。由于在构建此结果时实际线程集可能动态变化,因此返回的集合仅是最佳估计。返回集合的元素没有特定顺序。此方法旨在便于构建提供更广泛条件监控功能的子类。
      参数:
      condition - 条件
      返回值:
      线程集合
      抛出:
      IllegalMonitorStateException - 如果未持有此锁
      IllegalArgumentException - 如果给定条件与此锁不相关
      NullPointerException - 如果条件为null
    • toString

      public String toString()
      返回标识此锁及其锁状态的字符串。状态在括号中,包括字符串"Write locks ="后跟可重入持有的写锁数量,以及字符串"Read locks ="后跟持有的读锁数量。
      覆盖:
      toString 在类 Object
      返回值:
      标识此锁及其锁状态的字符串