模块 java.base

类 AbstractQueuedSynchronizer

java.lang.Object
java.util.concurrent.locks.AbstractOwnableSynchronizer
java.util.concurrent.locks.AbstractQueuedSynchronizer
所有已实现的接口:
Serializable

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements Serializable
提供一个框架,用于实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量、事件等)。此类旨在成为大多数依赖单个原子 int 值来表示状态的同步器的有用基础。子类必须定义更改此状态的受保护方法,并根据获取或释放此对象来定义该状态的含义。鉴于这些,此类中的其他方法执行所有排队和阻塞机制。子类可以维护其他状态字段,但只有使用方法 getState() setState(int) compareAndSetState(int, int) 操作的原子更新的 int 值在同步方面被跟踪。

子类应定义为非公共内部帮助程序类,用于实现其封闭类的同步属性。类 AbstractQueuedSynchronizer 没有实现任何同步接口。相反,它定义了诸如 acquireInterruptibly(int) 之类的方法,具体锁和相关同步器可以适当地调用这些方法来实现它们的公共方法。

此类支持默认 exclusive 模式和 shared 模式之一或两者。在独占模式下获取时,其他线程尝试获取不会成功。多个线程的共享模式获取可能(但不需要)成功。此类不“理解”这些差异,除了机械意义上的差异,即当共享模式获取成功时,下一个等待线程(如果存在)也必须确定它是否也可以获取。在不同模式下等待的线程共享同一个 FIFO 队列。通常,实现子类仅支持这些模式中的一种,但两者都可以发挥作用,例如在 ReadWriteLock 中。仅支持独占或共享模式的子类不需要定义支持未使用模式的方法。

此类定义了一个嵌套的 AbstractQueuedSynchronizer.ConditionObject 类,可用作支持独占模式的子类的 Condition 实现,其中方法 isHeldExclusively() 报告同步是否相对于当前线程以独占方式保持,使用当前 getState() 值调用的方法 release(int) 完全释放此对象,和 acquire(java.util.concurrent.locks.AbstractQueuedSynchronizer.Node, int, boolean, boolean, boolean, long) ,给定这个保存的状态值,最终将这个对象恢复到它之前获得的状态。没有 AbstractQueuedSynchronizer 方法否则会创建这样的条件,因此如果不能满足此约束,请不要使用它。 AbstractQueuedSynchronizer.ConditionObject 的行为当然取决于其同步器实现的语义。

此类提供内部队列的检查、检测和监控方法,以及条件对象的类似方法。这些可以根据需要导出到类中,使用AbstractQueuedSynchronizer 作为它们的同步机制。

此类的序列化仅存储维护状态的底层原子整数,因此反序列化对象具有空线程队列。需要可序列化的典型子类将定义一个readObject 方法,该方法在反序列化时将其恢复到已知的初始状态。

用法

要使用此类作为同步器的基础,请通过使用 getState() setState(int) 和/或 compareAndSetState(int, int) 检查和/或修改同步状态,重新定义以下方法(如果适用):

默认情况下,这些方法中的每一个都会抛出 UnsupportedOperationException 。这些方法的实现必须是内部线程安全的,并且通常应该很短并且不会阻塞。定义这些方法是 only 支持的使用此类的方法。所有其他方法都声明为final,因为它们不能独立变化。

您可能还会发现从 AbstractOwnableSynchronizer 继承的方法对于跟踪拥有独占同步器的线程很有用。我们鼓励您使用它们——这使监视和诊断工具能够帮助用户确定哪些线程持有锁。

即使此类基于内部 FIFO 队列,它也不会自动执行 FIFO 获取策略。独占同步的核心采用以下形式:

 Acquire: 
   while (!tryAcquire(arg)) {
    enqueue thread if it is not already queued ;
    possibly block current thread ;
   }

 Release: 
   if (tryRelease(arg))
    unblock the first queued thread ;
 
(共享模式类似,但可能涉及级联信号。)

因为获取中的检查是在排队之前调用的,所以新获取线程可能barge领先于其他被阻塞和排队的线程。但是,如果需要,您可以定义 tryAcquire 和/或 tryAcquireShared 以通过在内部调用一种或多种检查方法来禁用闯入,从而提供 fair FIFO 采集顺序。特别是,大多数公平同步器可以定义 tryAcquire 以在 hasQueuedPredecessors() (专门为公平同步器使用的方法)返回 true 时返回 false。其他变化是可能的。

默认插入(也称为 greedyrenouncementconvoy-avoidance)策略的吞吐量和可伸缩性通常最高。虽然这不能保证公平或无饥饿,但允许较早排队的线程在较晚排队的线程之前重新竞争,并且每次重新竞争都有机会成功对抗传入线程。此外,虽然获取不会在通常意义上“自旋”,但它们可能会执行多次调用 tryAcquire 并在阻塞之前穿插其他计算。当仅短暂保持独占同步时,这提供了自旋的大部分好处,而在不保持同步时没有大部分责任。如果需要,您可以通过在调用之前使用“快速路径”检查获取方法来增强这一点,可能预先检查 hasContended() 和/或 hasQueuedThreads() 以仅在可能不会竞争同步器时才这样做。

此类通过将其使用范围专门用于可以依赖int状态、获取和释放参数以及内部 FIFO 等待队列的同步器,部分地为同步提供了高效且可扩展的基础。当这还不够时,您可以使用 atomic 类、您自己的自定义 Queue 类和 LockSupport 阻塞支持从较低级别构建同步器。

使用示例

这里是一个不可重入的互斥锁类,使用值0表示解锁状态,1表示锁定状态。虽然不可重入锁并不严格要求记录当前所有者线程,但此类无论如何都会这样做,以便更容易监控使用情况。它还支持条件并公开一些检测方法:

 
 class Mutex implements Lock, java.io.Serializable {

  // Our internal helper class
  private static class Sync extends AbstractQueuedSynchronizer {
   // Acquires the lock if state is zero
   public boolean tryAcquire(int acquires) {
    assert acquires == 1; // Otherwise unused
    if (compareAndSetState(0, 1)) {
     setExclusiveOwnerThread(Thread.currentThread());
     return true;
    }
    return false;
   }

   // Releases the lock by setting state to zero
   protected boolean tryRelease(int releases) {
    assert releases == 1; // Otherwise unused
    if (!isHeldExclusively())
     throw new IllegalMonitorStateException();
    setExclusiveOwnerThread(null);
    setState(0);
    return true;
   }

   // Reports whether in locked state
   public boolean isLocked() {
    return getState() != 0;
   }

   public boolean isHeldExclusively() {
    // a data race, but safe due to out-of-thin-air guarantees
    return getExclusiveOwnerThread() == Thread.currentThread();
   }

   // Provides a Condition
   public Condition newCondition() {
    return new ConditionObject();
   }

   // Deserializes properly
   private void readObject(ObjectInputStream s)
     throws IOException, ClassNotFoundException {
    s.defaultReadObject();
    setState(0); // reset to unlocked state
   }
  }

  // The sync object does all the hard work. We just forward to it.
  private final Sync sync = new Sync();

  public void lock()       { sync.acquire(1); }
  public boolean tryLock()    { return sync.tryAcquire(1); }
  public void unlock()      { sync.release(1); }
  public Condition newCondition() { return sync.newCondition(); }
  public boolean isLocked()    { return sync.isLocked(); }
  public boolean isHeldByCurrentThread() {
   return sync.isHeldExclusively();
  }
  public boolean hasQueuedThreads() {
   return sync.hasQueuedThreads();
  }
  public void lockInterruptibly() throws InterruptedException {
   sync.acquireInterruptibly(1);
  }
  public boolean tryLock(long timeout, TimeUnit unit)
    throws InterruptedException {
   return sync.tryAcquireNanos(1, unit.toNanos(timeout));
  }
 } 

这是一个类似于 CountDownLatch 的闩锁类,除了它只需要一个 signal 来触发。因为闩锁是非独占的,所以它使用shared获取和释放方法。

 
 class BooleanLatch {

  private static class Sync extends AbstractQueuedSynchronizer {
   boolean isSignalled() { return getState() != 0; }

   protected int tryAcquireShared(int ignore) {
    return isSignalled() ? 1 : -1;
   }

   protected boolean tryReleaseShared(int ignore) {
    setState(1);
    return true;
   }
  }

  private final Sync sync = new Sync();
  public boolean isSignalled() { return sync.isSignalled(); }
  public void signal()     { sync.releaseShared(1); }
  public void await() throws InterruptedException {
   sync.acquireSharedInterruptibly(1);
  }
 } 
自从:
1.5
参见:
  • 构造方法详细信息

    • AbstractQueuedSynchronizer

      protected AbstractQueuedSynchronizer()
      创建一个初始同步状态为零的新 AbstractQueuedSynchronizer 实例。
  • 方法详情

    • getState

      protected final int getState()
      返回同步状态的当前值。此操作具有 volatile 读取的内存语义。
      返回:
      当前状态值
    • setState

      protected final void setState(int newState)
      设置同步状态的值。此操作具有 volatile 写入的内存语义。
      参数:
      newState - 新的状态值
    • compareAndSetState

      protected final boolean compareAndSetState(int expect, int update)
      如果当前状态值等于预期值,则以原子方式将同步状态设置为给定的更新值。此操作具有 volatile 读写的内存语义。
      参数:
      expect - 期望值
      update - 新值
      返回:
      true 如果成功。错误返回表示实际值不等于预期值。
    • tryAcquire

      protected boolean tryAcquire(int arg)
      尝试以独占模式获取。此方法应查询对象的状态是否允许以独占模式获取它,如果允许则获取它。

      此方法始终由执行获取的线程调用。如果此方法报告失败,acquire 方法可能会将线程排队(如果它尚未排队),直到其他线程发出释放信号为止。这可用于实现方法 Lock.tryLock()

      默认实现抛出 UnsupportedOperationException

      参数:
      arg - 获取参数。该值始终是传递给获取方法的值,或者是进入条件等待时保存的值。该值在其他方面是未解释的,可以代表您喜欢的任何东西。
      返回:
      true 如果成功。成功后,该对象已被获取。
      抛出:
      IllegalMonitorStateException - 如果获取会将该同步器置于非法状态。必须以一致的方式抛出此异常,同步才能正常工作。
      UnsupportedOperationException - 如果不支持独占模式
    • tryRelease

      protected boolean tryRelease(int arg)
      尝试设置状态以反映独占模式下的释放。

      该方法总是由执行释放的线程调用。

      默认实现抛出 UnsupportedOperationException

      参数:
      arg - 释放参数。该值始终是传递给释放方法的值,或者是进入条件等待时的当前状态值。该值在其他方面是未解释的,可以代表您喜欢的任何东西。
      返回:
      true 如果此对象现在处于完全释放状态,以便任何等待的线程都可以尝试获取;和 false 否则。
      抛出:
      IllegalMonitorStateException - 如果释放会将此同步器置于非法状态。必须以一致的方式抛出此异常,同步才能正常工作。
      UnsupportedOperationException - 如果不支持独占模式
    • tryAcquireShared

      protected int tryAcquireShared(int arg)
      尝试以共享模式获取。此方法应查询对象的状态是否允许以共享模式获取它,如果允许则获取它。

      此方法始终由执行获取的线程调用。如果此方法报告失败,acquire 方法可能会将线程排队(如果它尚未排队),直到其他线程发出释放信号为止。

      默认实现抛出 UnsupportedOperationException

      参数:
      arg - 获取参数。该值始终是传递给获取方法的值,或者是进入条件等待时保存的值。该值在其他方面是未解释的,可以代表您喜欢的任何东西。
      返回:
      失败时的负值;如果共享模式下的获取成功但后续共享模式获取无法成功,则为零;如果在共享模式下获取成功并且后续共享模式获取也可能成功,则为正值,在这种情况下,后续等待线程必须检查可用性。 (对三种不同返回值的支持使该方法可以在获取仅有时独占行为的上下文中使用。)成功后,该对象已被获取。
      抛出:
      IllegalMonitorStateException - 如果获取会将该同步器置于非法状态。必须以一致的方式抛出此异常,同步才能正常工作。
      UnsupportedOperationException - 如果不支持共享模式
    • tryReleaseShared

      protected boolean tryReleaseShared(int arg)
      尝试设置状态以反映共享模式下的释放。

      该方法总是由执行释放的线程调用。

      默认实现抛出 UnsupportedOperationException

      参数:
      arg - 释放参数。该值始终是传递给释放方法的值,或者是进入条件等待时的当前状态值。该值在其他方面是未解释的,可以代表您喜欢的任何东西。
      返回:
      true如果此共享模式版本可能允许等待获取(共享或独占)成功;和false否则
      抛出:
      IllegalMonitorStateException - 如果释放会将此同步器置于非法状态。必须以一致的方式抛出此异常,同步才能正常工作。
      UnsupportedOperationException - 如果不支持共享模式
    • isHeldExclusively

      protected boolean isHeldExclusively()
      如果同步相对于当前(调用)线程以独占方式保持,则返回 true。每次调用 AbstractQueuedSynchronizer.ConditionObject 方法时都会调用此方法。

      默认实现抛出 UnsupportedOperationException 。此方法仅在 AbstractQueuedSynchronizer.ConditionObject 方法内部调用,因此如果不使用条件则无需定义。

      返回:
      true 如果同步以独占方式进行; false否则
      抛出:
      UnsupportedOperationException - 如果不支持条件
    • acquire

      public final void acquire(int arg)
      以独占模式获取,忽略中断。通过至少调用一次 tryAcquire(int) 实现,成功返回。否则线程会排队,可能会重复阻塞和解除阻塞,调用 tryAcquire(int) 直到成功。此方法可用于实现方法 Lock.lock()
      参数:
      arg - 获取参数。这个值被传送给 tryAcquire(int) 但在其他方面没有解释,可以代表你喜欢的任何东西。
    • acquireInterruptibly

      public final void acquireInterruptibly(int arg) throws InterruptedException
      以独占模式获取,如果中断则中止。通过首先检查中断状态,然后至少调用一次 tryAcquire(int) ,成功返回来实现。否则线程将排队,可能会重复阻塞和解除阻塞,调用 tryAcquire(int) 直到成功或线程被中断。此方法可用于实现方法 Lock.lockInterruptibly()
      参数:
      arg - 获取参数。这个值被传送给 tryAcquire(int) 但在其他方面没有解释,可以代表你喜欢的任何东西。
      抛出:
      InterruptedException - 如果当前线程被中断
    • tryAcquireNanos

      public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException
      尝试以独占模式获取,如果中断则中止,如果给定的超时已过则失败。通过首先检查中断状态,然后至少调用一次 tryAcquire(int) ,成功返回来实现。否则,线程会排队,可能会重复阻塞和解除阻塞,调用 tryAcquire(int) 直到成功或线程被中断或超时结束。此方法可用于实现方法 Lock.tryLock(long, TimeUnit)
      参数:
      arg - 获取参数。这个值被传送给 tryAcquire(int) 但在其他方面没有解释,可以代表你喜欢的任何东西。
      nanosTimeout - 等待的最大纳秒数
      返回:
      true 如果获得; false 如果超时
      抛出:
      InterruptedException - 如果当前线程被中断
    • release

      public final boolean release(int arg)
      以独占模式发布。如果 tryRelease(int) 返回真,则通过取消阻塞一个或多个线程来实现。此方法可用于实现方法 Lock.unlock()
      参数:
      arg - 释放参数。这个值被传送给 tryRelease(int) 但在其他方面没有解释,可以代表你喜欢的任何东西。
      返回:
      tryRelease(int) 返回的值
    • acquireShared

      public final void acquireShared(int arg)
      以共享模式获取,忽略中断。通过首先调用至少一次 tryAcquireShared(int) 实现,成功返回。否则线程会排队,可能会重复阻塞和解除阻塞,调用 tryAcquireShared(int) 直到成功。
      参数:
      arg - 获取参数。这个值被传送给 tryAcquireShared(int) 但在其他方面没有解释,可以代表你喜欢的任何东西。
    • acquireSharedInterruptibly

      public final void acquireSharedInterruptibly(int arg) throws InterruptedException
      以共享模式获取,如果中断则中止。通过首先检查中断状态,然后至少调用一次 tryAcquireShared(int) ,成功返回来实现。否则线程将排队,可能会重复阻塞和解除阻塞,调用 tryAcquireShared(int) 直到成功或线程被中断。
      参数:
      arg - 获取参数。这个值被传送给 tryAcquireShared(int) 但在其他方面没有解释,可以代表你喜欢的任何东西。
      抛出:
      InterruptedException - 如果当前线程被中断
    • tryAcquireSharedNanos

      public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException
      尝试以共享模式获取,如果中断则中止,如果给定的超时已过则失败。通过首先检查中断状态,然后至少调用一次 tryAcquireShared(int) ,成功返回来实现。否则,线程会排队,可能会重复阻塞和解除阻塞,调用 tryAcquireShared(int) 直到成功或线程被中断或超时结束。
      参数:
      arg - 获取参数。这个值被传送给 tryAcquireShared(int) 但在其他方面没有解释,可以代表你喜欢的任何东西。
      nanosTimeout - 等待的最大纳秒数
      返回:
      true 如果获得; false 如果超时
      抛出:
      InterruptedException - 如果当前线程被中断
    • releaseShared

      public final boolean releaseShared(int arg)
      以共享模式发布。如果 tryReleaseShared(int) 返回 true,则通过取消阻塞一个或多个线程来实现。
      参数:
      arg - 释放参数。这个值被传送给 tryReleaseShared(int) 但在其他方面没有解释,可以代表你喜欢的任何东西。
      返回:
      tryReleaseShared(int) 返回的值
    • hasQueuedThreads

      public final boolean hasQueuedThreads()
      查询是否有任何线程正在等待获取。请注意,由于中断和超时导致的取消可能随时发生,true 返回不保证任何其他线程将获得。
      返回:
      true如果可能有其他线程等待获取
    • hasContended

      public final boolean hasContended()
      查询是否有线程争用过这个同步器;也就是说,如果 acquire 方法曾经被阻塞。

      在此实现中,此操作以恒定时间返回。

      返回:
      true 如果曾经有过争论
    • getFirstQueuedThread

      public final Thread  getFirstQueuedThread()
      返回队列中的第一个(等待时间最长的)线程,如果当前没有线程排队,则返回 null

      在此实现中,此操作通常以恒定时间返回,但如果其他线程正在并发修改队列,则可能会在争用时迭代。

      返回:
      队列中的第一个(等待时间最长的)线程,如果当前没有线程排队,则为 null
    • isQueued

      public final boolean isQueued(Thread  thread)
      如果给定线程当前正在排队,则返回 true。

      此实现遍历队列以确定给定线程的存在。

      参数:
      thread - 线程
      返回:
      true 如果给定线程在队列中
      抛出:
      NullPointerException - 如果线程为空
    • hasQueuedPredecessors

      public final boolean hasQueuedPredecessors()
      查询是否有任何线程等待获取的时间比当前线程长。

      此方法的调用等效于(但可能比以下更有效):

       
       getFirstQueuedThread() != Thread.currentThread()
        && hasQueuedThreads() 

      请注意,由于中断和超时导致的取消可能随时发生,true 返回不保证其他线程将在当前线程之前获取。同样,由于队列为空,在此方法返回 false 后,另一个线程有可能赢得入队竞争。

      此方法旨在供公平同步器使用以避免 闯入 。这样一个同步器的 tryAcquire(int) 方法应该返回 false ,并且它的 tryAcquireShared(int) 方法应该返回一个负值,如果这个方法返回 true (除非这是一个可重入获取)。例如,公平、可重入、独占模式同步器的 tryAcquire方法可能如下所示:

       
       protected boolean tryAcquire(int arg) {
        if (isHeldExclusively()) {
         // A reentrant acquire; increment hold count
         return true;
        } else if (hasQueuedPredecessors()) {
         return false;
        } else {
         // try to acquire normally
        }
       } 
      返回:
      true 如果在当前线程之前有一个排队的线程,并且 false 如果当前线程在队列的头部或队列为空
      自从:
      1.7
    • getQueueLength

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

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

      public final Collection <Thread > getExclusiveQueuedThreads()
      返回一个集合,其中包含可能正在等待以独占模式获取的线程。这与 getQueuedThreads() 具有相同的属性,只是它只返回那些因独占获取而等待的线程。
      返回:
      线程的集合
    • getSharedQueuedThreads

      public final Collection <Thread > getSharedQueuedThreads()
      返回一个集合,其中包含可能正在等待以共享模式获取的线程。这与 getQueuedThreads() 具有相同的属性,只是它只返回那些因共享获取而等待的线程。
      返回:
      线程的集合
    • toString

      public String  toString()
      返回标识此同步器及其状态的字符串。括号中的状态包括字符串 "State =" 后跟 getState() 的当前值,以及 "nonempty""empty" 取决于队列是否为空。
      重写:
      toString 在类 Object
      返回:
      标识此同步器及其状态的字符串
    • owns

      public final boolean owns(AbstractQueuedSynchronizer.ConditionObject  condition)
      查询给定的 ConditionObject 是否使用此同步器作为其锁。
      参数:
      condition - 条件
      返回:
      true 如果拥有
      抛出:
      NullPointerException - 如果条件为空
    • hasWaiters

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

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

      public final Collection <Thread > getWaitingThreads(AbstractQueuedSynchronizer.ConditionObject  condition)
      返回一个集合,其中包含可能正在等待与此同步器关联的给定条件的那些线程。因为实际的线程集在构造此结果时可能会动态变化,所以返回的集合只是尽力而为的估计。返回集合的元素没有特定的顺序。
      参数:
      condition - 条件
      返回:
      线程的集合
      抛出:
      IllegalMonitorStateException - 如果不保持独占同步
      IllegalArgumentException - 如果给定条件与此同步器无关
      NullPointerException - 如果条件为空