AbstractQueuedSynchronizer(AQS)源码深度解析
AbstractQueuedSynchronizer
(简称 AQS)是 Java 并发包(java.util.concurrent
)中的核心类之一,主要用于实现自定义同步器,如互斥锁、信号量、读写锁等。AQS 是一个抽象类,提供了多种方法来处理线程的同步操作,它的实现基于一个先进先出的(FIFO)的等待队列。
AQS 采用了一个 同步状态 来管理线程的访问权限,同时使用 等待队列 来协调多线程的竞争。通过对 AQS 源码的解析,我们可以更好地理解它如何在 Java 中提供高效的并发控制。
AQS 核心设计
- 同步状态 AQS 的同步状态通常是一个整数,表示同步资源的状态。它通过
getState()
、setState()
、compareAndSetState()
等方法来获取和修改这个状态。 - 等待队列 AQS 使用一个 FIFO 队列 来管理那些被阻塞的线程。每个线程在等待时都会被封装成一个 节点,这些节点会按顺序排列在队列中。AQS 通过这个队列来控制线程的排队顺序。
- 独占与共享模式 AQS 支持两种模式:独占模式 和 共享模式。独占模式下只有一个线程能够获取同步状态;共享模式下多个线程可以共享同步资源。
AQS 重要方法解析
acquire()
和release()
acquire()
:用于获取同步状态。线程会被阻塞,直到同步状态可用为止。release()
:释放同步状态,使得其他等待的线程可以获取到该状态。
tryAcquire()
和tryRelease()
这些方法是实现自定义同步器的关键方法,它们需要被子类实现。tryAcquire()
用于尝试获取同步状态,tryRelease()
用于尝试释放同步状态。acquireShared()
和releaseShared()
这两个方法用于共享模式下的同步控制。当资源可以被多个线程共享时,acquireShared()
会尝试获得共享状态,releaseShared()
会释放共享状态。isHeldExclusively()
该方法用于判断当前同步器是否被某个线程独占。它是判断同步器状态是否为独占状态的标准。
AQS 的工作原理
- 线程获取锁 线程通过
acquire()
方法尝试获取同步状态。若同步状态可用,则线程直接获取;若不可用,线程会被挂起并放入等待队列中。 - 线程释放锁 当线程完成任务并调用
release()
方法时,它会将同步状态释放,唤醒队列中的一个或多个等待线程。 - 等待队列 当线程被阻塞时,它会被加入到 AQS 的等待队列中。等待队列中的线程是先进先出(FIFO)排队的,保证了公平性。
- 共享模式 在共享模式下,多个线程可以同时获取同步状态。例如,信号量和读写锁的实现就是基于共享模式的。
AQS 源码解析
AQS 类的主要成员变量
// AQS 内部的一个节点类,用于表示等待队列中的每个节点。
private static final class Node {
static final Node EXCLUSIVE = null; // 独占模式
static final Node SHARED = new Node(); // 共享模式
volatile Thread thread; // 该节点所代表的线程
volatile Node next; // 下一个节点
volatile Node prev; // 上一个节点
volatile int waitStatus; // 节点的等待状态
volatile Node nextWaiter; // 下一个等待者节点
}
等待队列的管理
AQS 内部维护着一个等待队列,通过 enqueue(Node node)
方法将线程节点加入队列:
// 将节点加入队列
private Node enqueue(Node node) {
// 获取队列的最后一个节点
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return pred;
}
}
return head;
}
获取同步状态
// 通过 CAS 操作获取同步状态
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
AQS 的使用场景
- 锁的实现 AQS 是实现 Java 中
ReentrantLock
、ReentrantReadWriteLock
等自定义锁的基础。它通过 独占模式 来实现一个线程获取锁,而其他线程等待。 - 信号量 在信号量的实现中,AQS 使用 共享模式 来允许多个线程并发访问资源。例如,
Semaphore
类就是基于 AQS 实现的,它允许多个线程共享访问。 - 计数器 AQS 可以用于实现各种计数器,例如
CountDownLatch
和CyclicBarrier
,这些计数器的实现都基于 AQS 的同步状态管理和线程的等待机制。
AQS 的优缺点
优点
- 高效性:AQS 通过自旋和 CAS 操作来减少上下文切换,提高性能。
- 灵活性:AQS 支持多种同步模式,能够实现各种同步器(如独占、共享模式的锁和信号量)。
- 可扩展性:用户可以通过继承 AQS 类来实现自定义的同步器。
缺点
- 复杂性:AQS 的实现比较复杂,理解和调试困难,尤其是等待队列和同步状态的管理。
- 公平性问题:尽管 AQS 支持公平性控制,但默认是非公平的,可能会导致线程饥饿等问题。
总结
AbstractQueuedSynchronizer
(AQS)是 Java 并发工具包的一个核心组件,提供了一个框架用于实现锁、信号量、计数器等多种同步机制。它通过同步状态和等待队列来管理线程的访问,支持独占模式和共享模式。理解 AQS 的实现原理,能够帮助开发者更好地构建高效的并发应用。
版权声明:
作者:admin
链接:https://www.tsycdn.com/waf/542.html
文章版权归作者所有,未经允许请勿转载。
THE END