Module java.base

Class 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)之类的方法,可以由具体的锁和相关同步器适当地调用以实现它们的公共方法。

这个类支持默认的独占模式和共享模式中的一个或两个。在独占模式下获取时,其他线程尝试获取将无法成功。多个线程以共享模式获取可能(但不一定)会成功。这个类不“理解”这些差异,除了在机械意义上,当共享模式获取成功时,下一个等待的线程(如果存在)也必须确定它是否也可以获取。在不同模式下等待的线程共享相同的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。这些方法的实现必须在内部是线程安全的,并且通常应该是简短的且不会阻塞。定义这些方法是唯一支持使用这个类的方法。所有其他方法都声明为final,因为它们不能独立变化。

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

尽管这个类基于内部FIFO队列,但它不会自动强制执行FIFO获取策略。独占同步的核心形式如下:

 获取:
     while (!tryAcquire(arg)) {
        如果尚未排队,则将线程排队;
        可能阻塞当前线程;
     }

 释放:
     if (tryRelease(arg))
        解除阻塞第一个排队的线程;
 
(共享模式类似,但可能涉及级联信号。)

因为在获取时调用的检查在排队之前,新获取的线程可能会插队到其他被阻塞和排队的线程之前。但是,如果需要,您可以通过定义tryAcquire和/或tryAcquireShared来禁用插队,内部调用一个或多个检查方法,从而提供一个公平的FIFO获取顺序。特别是,大多数公平同步器可以定义tryAcquire,如果hasQueuedPredecessors()(专门设计用于公平同步器使用的方法)返回true,则返回false。其他变体也是可能的。

默认插队(也称为贪婪放弃避免车队)策略通常具有最高的吞吐量和可伸缩性。虽然不能保证是公平的或无饥饿的,但先前排队的线程被允许在后排队的线程之前重新竞争,并且每次重新竞争都有一个无偏见的机会成功对抗新到来的线程。此外,虽然获取不会以通常意义上的“自旋”方式进行,但它们可能在阻塞之前执行多次调用tryAcquire,并与其他计算交替进行。当独占同步仅短暂持有时,这提供了自旋的大部分好处,而在不持有时则没有大部分的责任。如果需要,您可以通过在调用获取方法之前增加“快速路径”检查,可能预先检查hasContended()和/或hasQueuedThreads(),只有在同步器可能不会被争用时才这样做。

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

用法示例

这是一个非重入互斥锁类的示例,它使用值零表示未锁定状态,使用值一表示已锁定状态。虽然非重入锁不严格要求记录当前所有者线程,但这个类仍然这样做是为了使使用更容易监视。它还支持条件并公开一些检测方法:

 
 class Mutex implements Lock, java.io.Serializable {

   // 我们的内部辅助类
   private static class Sync extends AbstractQueuedSynchronizer {
     // 如果状态为零,则获取锁
     public boolean tryAcquire(int acquires) {
       assert acquires == 1; // 否则未使用
       if (compareAndSetState(0, 1)) {
         setExclusiveOwnerThread(Thread.currentThread());
         return true;
       }
       return false;
     }

     // 通过将状态设置为零来释放锁
     protected boolean tryRelease(int releases) {
       assert releases == 1; // 否则未使用
       if (!isHeldExclusively())
         throw new IllegalMonitorStateException();
       setExclusiveOwnerThread(null);
       setState(0);
       return true;
     }

     // 报告是否处于锁定状态
     public boolean isLocked() {
       return getState() != 0;
     }

     public boolean isHeldExclusively() {
       // 一个数据竞争,但由于无中生有的保证是安全的
       return getExclusiveOwnerThread() == Thread.currentThread();
     }

     // 提供一个Condition
     public Condition newCondition() {
       return new ConditionObject();
     }

     // 正确反序列化
     private void readObject(ObjectInputStream s)
         throws IOException, ClassNotFoundException {
       s.defaultReadObject();
       setState(0); // 重置为未锁定状态
     }
   }

   // sync对象完成所有繁重的工作。我们只需转发给它。
   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获取和释放方法。

 
 类 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);
   }
 }
自JDK版本:
1.5
参见:
  • Constructor Details

    • AbstractQueuedSynchronizer

      protected AbstractQueuedSynchronizer()
      创建一个具有初始同步状态为零的新 AbstractQueuedSynchronizer 实例。
  • Method Details

    • 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。返回 false 表示实际值与期望值不相等。
    • tryAcquire

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

      此方法始终由执行获取的线程调用。如果此方法报告失败,则获取方法可能会将线程排队,如果尚未排队,则直到被其他线程的释放信号唤醒。这可用于实现方法 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)
      尝试以共享模式获取。此方法应查询对象的状态是否允许以共享模式获取,并在允许时获取它。

      此方法始终由执行获取的线程调用。如果此方法报告失败,则获取方法可能会将线程排队,如果尚未排队,则直到被其他线程的释放信号唤醒。

      默认实现会抛出 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)返回true,则通过解除阻塞一个或多个线程来实现。此方法可用于实现方法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()
      查询是否有任何线程曾经争夺获取此同步器;也就是说,是否曾经阻塞过获取方法。

      在此实现中,此操作在常量时间内返回。

      返回:
      如果曾经存在争夺,则返回true
    • getFirstQueuedThread

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

      在此实现中,此操作通常在常量时间内返回,但如果其他线程同时修改队列,则可能会迭代争用。

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

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

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

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

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

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

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

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

      此方法设计用于公平同步器,以避免插队。如果此方法返回true(除非这是可重入获取),则公平同步器的tryAcquire(int)方法应返回false,其tryAcquireShared(int)方法应返回负值。例如,公平、可重入、独占模式同步器的tryAcquire方法可能如下所示:

       
       protected boolean tryAcquire(int arg) {
         if (isHeldExclusively()) {
           // 可重入获取;增加持有计数
           return true;
         } else if (hasQueuedPredecessors()) {
           return false;
         } else {
           // 尝试正常获取
         }
       }
      返回:
      如果存在排在当前线程前面的排队线程,则返回true;如果当前线程在队列头部或队列为空,则返回false
      自1.7起
      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 - 如果条件为 null
    • hasWaiters

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

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

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