一、简介
- AQS,即
AbstractQueuedSynchronizer,抽象队列同步器。
- 简单来说,就是通过AQS对多个线程的状态进行管理,park状态、unpark状态之间进行转换。
- AQS内部通过双向链表实现,线程以先进先出的顺序执行。
- JUC的多个应用类,内部都是通过AQS实现的。
- 以下以
ReentrantLock为例进行讲解。
二、ReetrantLock

ReentrantLock内部有三个内部类,分为公平锁和非公平锁。而它们的基类都是Sync,Sync的父类是AQS
ReentrantLock默认使用的是非公平锁,即刚进来的线程有可能因为幸运,一进来就插队抢到执行权,而队列的头结点也有可能动作比较慢被抢执行权。
Sync有一个最重要的抽象方法,分别由NonfairSync和FairSync予以不同的方式实现。
abstract void lock();
1. lock()
- 而两个不同最大的不同就是,是否让刚进来的线程通过CAS尝试获取执行权。
static final class NonfairSync extends Sync {
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
}
static final class FairSync extends Sync {
final void lock() {
acquire(1);
}
}
2. compareAndSetState()
- 到这值得一提的是,在
NonfairSync中,compareAndSetState()的state是什么意思。
- 在AQS中,有一个成员属性是
state,这个量标志着目前AQS正在处于什么工作状态。0表示没有线程在执行,1表示存在线程正在执行。
private volatile int state;
- 因此对于
NonfairSync中的compareAndSetState()也可以理解了,意思就是如果目前state为0,就抢占先机,自己把它设置为1,然后再进去工作。
3. setExclusiveOwnerThread()
- 如果设置成功之后,就直接通过
setExclusiveOwnerThread()将自己的线程设置为执行的主线程,直接上位了。
- 此方法在
AbstractOwnableSynchronizer类中,是AQS的父类。
public abstract class AbstractOwnableSynchronizer
implements java.io.Serializable {
private transient Thread exclusiveOwnerThread;
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
protected final Thread getExclusiveOwnerThread() {
return exclusiveOwnerThread;
}
}

4. acquire()
- 这是
AQS的方法
- 如果没抢占到,线程就进入正常的操作中了。此方法在非公平锁和公平锁中都是一样的。
- 此方法在AQS内
- 首先尝试获取线程,
tryAcquire()是重要的方法。
- 尝试进入队列,首先通过
addWaiter()生成一个队列节点Node,然后acquireQueued()放入队列,并阻塞等待。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
5. tryAcquire()
- 这个方法非常常用,在往后的操作中也会使用到,表示尝试获取线程执行权。
- 而该方法在AQS中是一个抽象方法,需要子类实现。
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
- 方法有两个最重要的尝试:
- 如果目前队列没有要执行的线程且
state为0,就通过CAS占用;
- 如果自己的线程和正在执行的线程是同一个线程,就表示这是一个可重入锁(也就是在
lock()里面又lock()了一遍),在原来的state基础上加上自己的参数,而解锁的时候,需要像栈一样,将所有lock()都解掉。
- 如果该方法返回
true,上面的acquire()方法就表示执行结束了,该线程的处理也就完毕了。
6. addWaiter()
- 如果上面的方法为
false,则需要执行acquireQueued()方法了。不过在执行该方法之前,还需要执行一个添加节点的操作。
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
- 此方法一开始就新建一个
Node,利用Node保存当前线程及模式(用于之后添加到队列中)。Node的相关信息,下一节介绍。
- 然后尝试获取该队列的尾结点,如果存在,就将新节点添加到尾结点处。然后返回
node
- 如果目前尾节点还不存在,说明现在是一个新的队列,还需要进行一些操作,因此,就进入了
enq()方法中。
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) {
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
- 该方法很巧妙,做了一个循环结构,一开始
tail==null,因此新建一个节点,并让头指针和尾指针都指向它。
- 后来,让新的节点插入到尾节点后面,然后返回。
- 至此,完成了
Node的入队操作。
7. Node
- 在此,插入一个简单的解释。
Node是用于封装线程及其属性的一个类,存放在AQS中。
static final class Node {
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
Node nextWaiter;
}
8. acquireQueued()
- 上两节,新生成了一个队列的节点,并放入到队列,现在就可以尝试排队等待了。
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null;
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
- 这段代码有两个关键的地方,都通过注释标注了。
- 如果自己是下一个结点,且获取执行成功,那就将自己设为下一个头结点
- 如果上一个条件不满足,就会进入
shouldParkAfterFailedAcquire()方法,修改等待状态为阻塞态;并且parkAndCheckInterrupt()方法,进入真正的阻塞态。
9. shouldParkAfterFailedAcquire()
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
10. parkAndCheckInterrupt()
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
- 至此,完成了该线程尝试获取
lock()的全部过程,后面就是等待解锁的过程了。
11. unlock()
- 其他的线程想被解锁,必须要有一个线程解开锁。
- 这是
ReentrantLock的解锁操作
public void unlock() {
sync.release(1);
}
12. release()
- 在AQS中,有解锁的具体操作。而这个方法又调用一个
tryRelease()方法,尝试释放,如果释放已经成功了,那就unparkSuccessor()唤醒下一个执行的线程。
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
13. tryRelease()
Sync中有它的具体实现。该方法主要是用于解掉当前锁的状态,但至于能不能彻底释放,让其他线程进来,还要看这个锁外面还有没有锁。
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
14. unparkSuccessor()
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}