AQS
抽象队列同步器是JDK提供的用于管理线程间同步状态的类。常见的同步器类ReentrantLock, CountDownLatch, Semaphore等都是AbstractQueuedSynchronizer的子类。
AQS提供三个功能
- 提供同步状态。一个是state属性,管理资源的状态。一个是AQS的父抽象类的exclusiveOwnerThread,标记占有资源的线程。
- 提供FIFO等待队列。提供线程对象入队、出队、清理无效节点等功能。
- 提供条件队列。
状态 state
private volatile int state;
state表示资源的状态,线程根据state判断是否可以争抢资源。以独占模式(同时只能有1个线程获取资源)为例,state=1代表有某个线程掌握资源,exclusiveOwnerThread变量指向该线程。如果某个线程没成功争抢资源,那么进入同步队列,进入休眠,等待唤醒。
同步队列
线程对象是Thread
,但是同步队列管理的对象是Node
,从下面代码片段可以看出,Node
是对Thread
的封装以适应队列。
abstract static class Node {
volatile Node prev; // initially attached via casTail
volatile Node next; // visibly nonnull when signallable
Thread waiter; // visibly nonnull when enqueued
volatile int status;
}
status
与state
不同,status
是Node
的状态,源码中标记三种情况,还有第四种状态0
,代表初始化状态,此状态的节点会尝试获取资源,如果未获取变为WAITING
,如果有条件变为COND
,如果被踢出队列则变为CANCELLED
,这是唯一一个小于0的状态。
static final int WAITING = 1; // must be 1
static final int CANCELLED = 0x80000000; // must be negative
static final int COND = 2; // in a condition wait
同步队列是双向链表,链表的头节点是一个哑节点,用于标记链表。AQS维护head和tail变量。Node
可以分为链表Node
和游离Node
(Node D, Node E
)。获取锁,游离节点都可以争抢,链表节点中第一个工作节点(Node A
)可以争抢,其余节点不可以争抢。
争夺资源
acquire(int arg)
是AQS提供的争夺资源方法。
public final void acquire(int arg) {
if (!tryAcquire(arg))
acquire(null, arg, false, false, false, 0L);
}
首先tryAcquire
,AQS本身不定义该方法。这是AQS的实现类定义的获取锁的方法。以ReentrantLock
类的NonfairSync
非公平同步器为例,它根据state
判断是否能获取锁。
protected final boolean tryAcquire(int acquires) {
if (getState() == 0 && compareAndSetState(0, acquires))