AbstractQueuedSynchronizer简介

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic int value to represent state. Subclasses must define the protected methods that change this state, and which define what that state means in terms of this object being acquired or released. Given these, the other methods in this class carry out all queuing and blocking mechanics. Subclasses can maintain other state fields, but only the atomically updated int value manipulated using methods getState, setState and compareAndSetState is tracked with respect to synchronization.

AQS提供了一个框架,用于实现阻塞锁及相关同步器(如信号量、事件等),这些机制依赖于先进先出(FIFO)等待队列。该类旨在为大多数依赖单个原子整数值表示状态的同步器提供基础实现。子类必须定义受保护的方法来修改该状态值,并明确该状态在对象被获取或释放时的具体含义。基于这些定义,本类中的其他方法将处理所有排队和阻塞机制。子类可维护其他状态字段,但仅通过getStatesetStatecompareAndSetState方法操作的原子整数值会被用于同步跟踪。

Subclasses should be defined as non-public internal helper classes that are used to implement the synchronization properties of their enclosing class. Class AbstractQueuedSynchronizer does not implement any synchronization interface. Instead it defines methods such as acquireInterruptibly that can be invoked as appropriate by concrete locks and related synchronizers to implement their public methods.

子类应被定义为非公开的内部辅助类,用于实现其外围类的同步特性。AbstractQueuedSynchronizer 类本身不实现任何同步接口,而是定义了诸如 acquireInterruptibly 等方法,具体的锁及相关同步器可通过适当调用这些方法来实现其公共功能。

This class supports either or both a default exclusive mode and a shared mode. When acquired in exclusive mode, attempted acquires by other threads cannot succeed. Shared mode acquires by multiple threads may (but need not) succeed. This class does not "understand" these differences except in the mechanical sense that when a shared mode acquire succeeds, the next waiting thread (if one exists) must also determine whether it can acquire as well. Threads waiting in the different modes share the same FIFO queue. Usually, implementation subclasses support only one of these modes, but both can come into play for example in a ReadWriteLock. Subclasses that support only exclusive or only shared modes need not define the methods supporting the unused mode.

该类支持默认的独占模式、共享模式中的一种或两种。当以独占模式获取资源时,其他线程的尝试获取操作均无法成功;而多个线程以共享模式获取资源时可能(但非必须)成功。AQS 本身并不“理解”这些模式的语义差异,其唯一能识别的机制是:当一个共享模式获取成功时,必须检查下一个等待线程(如果存在)是否也能获取资源。不同模式下的等待线程共享同一个 FIFO 队列。通常,实现子类仅支持其中一种模式,但在某些场景(如 ReadWriteLock 读写锁)中两种模式会同时生效。仅支持独占或共享模式的子类无需定义未使用模式对应的方法。

This class defines a nested AbstractQueuedSynchronizer.ConditionObject class that can be used as a Condition implementation by subclasses supporting exclusive mode for which method isHeldExclusively reports whether synchronization is exclusively held with respect to the current thread, method release invoked with the current getState value fully releases this object, and acquire, given this saved state value, eventually restores this object to its previous acquired state. No AbstractQueuedSynchronizer method otherwise creates such a condition, so if this constraint cannot be met, do not use it. The behavior of AbstractQueuedSynchronizer.ConditionObject depends of course on the semantics of its synchronizer implementation.

该类定义了一个嵌套的 AbstractQueuedSynchronizer.ConditionObject 内部类,可作为 Condition 的实现,供支持独占模式的子类使用。但使用该条件对象需满足以下前提:

1、isHeldExclusively() 方法能正确报告当前线程是否独占持有同步资源;
2、调用 release() 并传入当前 getState() 返回值时,必须完全释放同步对象;
3、调用 acquire() 并传入之前保存的状态值后,必须能恢复到先前的获取状态。 若无法满足上述约束,则禁止使用此条件对象。
此外,AbstractQueuedSynchronizer 不会自动创建此类条件对象,且 ConditionObject 的行为完全取决于其同步器实现的具体语义。

This class provides inspection, instrumentation, and monitoring methods for the internal queue, as well as similar methods for condition objects. These can be exported as desired into classes using an AbstractQueuedSynchronizer for their synchronization mechanics.
Serialization of this class stores only the underlying atomic integer maintaining state, so deserialized objects have empty thread queues. Typical subclasses requiring serializability will define a readObject method that restores this to a known initial state upon deserialization.

该类为内部队列及条件对象提供了检查、检测和监控方法。这些方法可按需暴露给使用 AQS 实现同步机制的类。

在序列化时,该类仅存储维护状态的基础原子整型变量(state),因此反序列化后的对象将持有空的线程队列。需要支持序列化的典型子类应定义 readObject 方法,在反序列化时将对象恢复到已知的初始状态。

Usage 使用

To use this class as the basis of a synchronizer, redefine the following methods, as applicable, by inspecting and/or modifying the synchronization state using getState, setState and/or compareAndSetState:

  • tryAcquire
  • tryRelease
  • tryAcquireShared
  • tryReleaseShared
  • isHeldExclusively

若要将此类用作同步器的基础,请根据需求通过以下方法重新定义相关逻辑:使用 getStatesetState 和/或 compareAndSetState 来检测和修改同步状态:

  • tryAcquire
  • tryRelease
  • tryAcquireShared
  • tryReleaseShared
  • isHeldExclusively

Each of these methods by default throws UnsupportedOperationException. Implementations of these methods must be internally thread-safe, and should in general be short and not block. Defining these methods is the only supported means of using this class. All other methods are declared final because they cannot be independently varied.

这些方法在默认实现中均抛出 UnsupportedOperationException。其具体实现必须保证内部线程安全,且通常应保持简短、非阻塞。定义这些方法是使用此类的唯一受支持方式。所有其他方法均声明为 final,因其核心逻辑不可被独立修改。

You may also find the inherited methods from AbstractOwnableSynchronizer useful to keep track of the thread owning an exclusive synchronizer. You are encouraged to use them -- this enables monitoring and diagnostic tools to assist users in determining which threads hold locks.

您可能还会发现从 AbstractOwnableSynchronizer 继承的方法非常有用,它们能帮助追踪独占同步器的持有线程。我们强烈建议使用这些方法——这将使监控和诊断工具能够辅助用户确定哪些线程持有锁。

Even though this class is based on an internal FIFO queue, it does not automatically enforce FIFO acquisition policies. The core of exclusive synchronization takes the form:

尽管该类基于内部 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;

(Shared mode is similar but may involve cascading signals.)

(共享模式与此类似,但可能涉及级联信号。)

Because checks in acquire are invoked before enqueuing, a newly acquiring thread may barge ahead of others that are blocked and queued. However, you can, if desired, define tryAcquire and/or tryAcquireShared to disable barging by internally invoking one or more of the inspection methods, thereby providing a fair FIFO acquisition order. In particular, most fair synchronizers can define tryAcquire to return false if hasQueuedPredecessors (a method specifically designed to be used by fair synchronizers) returns true. Other variations are possible.

由于获取资源前的检查操作在入队前执行,新请求的线程可能抢先于已阻塞并排队的线程获取资源。然而,您可以通过在 tryAcquire 和/或 tryAcquireShared 方法内部调用检查方法来禁用插队行为,从而实现公平的 FIFO 获取顺序。具体而言,大多数公平同步器可定义:当 hasQueuedPredecessors(专为公平同步器设计的方法)返回 true 时,tryAcquire 返回 false。当然也存在其他变体实现。

Throughput and scalability are generally highest for the default barging (also known as greedy, renouncement, and convoy-avoidance) strategy. While this is not guaranteed to be fair or starvation-free, earlier queued threads are allowed to recontend before later queued threads, and each recontention has an unbiased chance to succeed against incoming threads. Also, while acquires do not "spin" in the usual sense, they may perform multiple invocations of tryAcquire interspersed with other computations before blocking. This gives most of the benefits of spins when exclusive synchronization is only briefly held, without most of the liabilities when it isn't. If so desired, you can augment this by preceding calls to acquire methods with "fast-path" checks, possibly prechecking hasContended and/or hasQueuedThreads to only do so if the synchronizer is likely not to be contended.

默认的插队策略(也称为贪婪策略、放弃策略或避免护航策略)通常能提供最高的吞吐量和可扩展性。虽然它不保证公平性或完全避免饥饿,但较早排队的线程会被允许比较晚排队的线程优先重新竞争资源,且每次重新竞争都有均等机会战胜新来的线程。此外,虽然获取操作在传统意义上不会"自旋",但在阻塞前可能多次调用 tryAcquire 并穿插其他计算。当独占同步状态仅被短暂持有时,这能带来自旋的大部分优势,同时规避了长期持有时的风险。如果需要,您可以通过在调用获取方法前添加"快速路径"检查来增强此机制,例如预先检查 hasContended 和/或 hasQueuedThreads 方法,仅在同步器可能无竞争时才尝试获取。

This class provides an efficient and scalable basis for synchronization in part by specializing its range of use to synchronizers that can rely on int state, acquire, and release parameters, and an internal FIFO wait queue. When this does not suffice, you can build synchronizers from a lower level using atomic classes, your own custom java.util.Queue classes, and LockSupport blocking support.

该类通过将适用范围限定在依赖 int 型状态、acquire/release 参数及内部 FIFO 等待队列的同步器上,从而为同步机制提供了高效且可扩展的基础。若此框架无法满足需求,您可通过原子类、自定义 java.util.Queue 实现以及 LockSupport 阻塞支持,从更底层构建同步器。

此设计体现了 AQS 的高性能哲学:通过可控的非公平性换取吞吐量,用智能重试替代盲目自旋,以最小代价实现线程协作,成为 Java 并发库的基石。

Usage Examples 使用示例

Here is a non-reentrant mutual exclusion lock class that uses the value zero to represent the unlocked state, and one to represent the locked state. While a non-reentrant lock does not strictly require recording of the current owner thread, this class does so anyway to make usage easier to monitor. It also supports conditions and exposes one of the instrumentation methods:

这是一个非可重入互斥锁类,它使用值 0 表示解锁状态,值 1 表示加锁状态。虽然非可重入锁并不严格要求记录当前持有线程,但此类仍然实现了此功能,以便更轻松地监控使用情况。它还支持条件变量,并公开了其中一种监控方法:

class Mutex implements Lock, java.io.Serializable {

  // Our internal helper class
  private static class Sync extends AbstractQueuedSynchronizer {
    // Reports whether in locked state
    protected boolean isHeldExclusively() {
      return getState() == 1;
    }

    // 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 (getState() == 0) throw new IllegalMonitorStateException();
      setExclusiveOwnerThread(null);
      setState(0);
      return true;
    }

    // Provides a Condition
    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.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));
  }

Here is a latch class that is like a CountDownLatch except that it only requires a single signal to fire. Because a latch is non-exclusive, it uses the shared acquire and release methods.

这是一个类似于 CountDownLatchlatch 类,但仅需一次信号即可触发。由于 latch 是非独占的,因此它使用共享模式的 acquirerelease 方法。

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);
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容