模块 java.base

类 ReentrantReadWriteLock

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

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

此类具有以下属性:

  • 收购订单

    此类不强加读者或作者对锁访问的偏好排序。但是,它确实支持可选的 fairness 策略。

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

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

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

  • 重入

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

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

  • 锁定降级

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

  • 中断获取锁

    读锁和写锁都支持获取锁时中断。

  • Condition 支持

    写锁提供了一个 Condition 实现,其行为方式与写锁相同,就像 ReentrantLock.newCondition() 提供的 Condition 实现对 ReentrantLock 所做的一样。当然,Condition 只能与写锁一起使用。

    读锁不支持 Condition readLock().newCondition() 抛出 UnsupportedOperationException

  • Instrumentation

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

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

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

 
 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 可用于提高某些类型集合的某些使用中的并发性。这通常只有在预期集合很大、由比写入线程更多的读取线程访问并且需要的开销超过同步开销的操作时才值得。例如,这里有一个使用 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
参见:
  • 构造方法详细信息

    • ReentrantReadWriteLock

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

      public ReentrantReadWriteLock(boolean fair)
      使用给定的公平策略创建一个新的 ReentrantReadWriteLock
      参数:
      fair - true 如果这个锁应该使用公平排序策略
  • 方法详情

    • 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()
      查询当前线程持有此锁的可重入读取次数。对于与解锁操作不匹配的每个锁定操作,读取器线程都持有一个锁。
      返回:
      当前线程持有读锁的次数,如果读锁未被当前线程持有则为零
      自从:
      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 - 如果线程为空
    • getQueueLength

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

      protected Collection <Thread > getQueuedThreads()
      返回一个集合,其中包含可能正在等待获取读锁或写锁的线程。因为实际的线程集在构造此结果时可能会动态变化,所以返回的集合只是尽力而为的估计。返回集合的元素没有特定的顺序。此方法旨在促进提供更广泛的监视功能的子类的构造。
      返回:
      线程的集合
    • hasWaiters

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

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

      protected Collection <Thread > getWaitingThreads(Condition  condition)
      返回一个集合,其中包含那些可能正在等待与写锁关联的给定条件的线程。因为实际的线程集在构造此结果时可能会动态变化,所以返回的集合只是尽力而为的估计。返回集合的元素没有特定的顺序。此方法旨在促进提供更广泛的状态监视功能的子类的构建。
      参数:
      condition - 条件
      返回:
      线程的集合
      抛出:
      IllegalMonitorStateException - 如果这个锁没有被持有
      IllegalArgumentException - 如果给定条件与此锁无关
      NullPointerException - 如果条件为空
    • toString

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