AQS
抽象队列同步器,定义了一套多线程访问共享资源的同步器,许多同步类的实现都依赖于AQS,如ReentrantLock、Semaphore。自定义同步器需要实现共享资源state的获取与释放,等待队列的维护(入队与唤醒出队)由AQS实现。
结点状态(int类型,初始化为0)
- CANCELLED(1)
结点取消调度,当timeout或者被中断的情况下,会触发变更为此状态 - SIGNAL(-1)
结点等待被通知唤醒,当结点入列时会将前一结点的状态变更为此状态 - CONDITION(-2)
结点等待在Condition上,当其他线程调用Condition的signal()方法后,该状态的结点会从等待队列转义到同步队列 - PROPAGATE(-3)
共享模式 - 0
新结点的默认状态
成员变量
- head
头结点 - tail
尾结点 - state
同步资源
成员方法:
- acquire(int)
以独占的方式获取资源,若获取成功则直接返回,否则进入等待队列直至被唤醒再次尝试获取资源。
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {
selfInterrupt();
}
}
- tryAcquire(int)
自定义实现方法,尝试获取资源。成功返回true,失败返回false。注意该方法需保证线程安全。 - addWaiter(Node)
将当前线程的结点加入到队尾,并返回当前线程的结点。
private Node addWaiter(Node mode) {
//根据给定模式构造结点(EXCLUSIVE(独占)和SHARED(共享))
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)方法插入队尾
enq(node);
return node;
}
- enq(Node)
执行完之后队列为:EmptyNode -> Node1
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;
}
}
}
}
- acquireQueued(Node, arg)
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
//该方法会在第一次执行循环体后,自旋进入第二次循环并在shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()处挂起
for (;;) {
//获取前结点前一个结点
final Node p = node.predecessor();
//仅头结点的下一个结点可执行tryAcquire方法
if (p == head && tryAcquire(arg)) {
//获取资源成功,设置当前节点为头结点,头结点GC,return false
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//把当前节点和前一结点作为参数,调用shouldParkAfterFailedAcquire
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
- shouldParkAfterFailedAcquire(Node pred, Node node)
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
//前一结点的waitStatus
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
若为SIGNAL,则返回true,挂起等待唤醒
return true;
if (ws > 0) {
//若>0,则说明该结点取消调度,删除该结点直至不出现>0的情况
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//设置前一结点的waitStatus为SIGNAL
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
- parkAndCheckInterrupt
private final boolean parkAndCheckInterrupt() {
//挂起当前线程
LockSupport.park(this);
//被唤醒或中断后返回当前线程的中断状态
return Thread.interrupted();
}
- release(int)
public final boolean release(int arg) {
//尝试释放资源,成功则唤醒头结点的下一结点,并设置头结点的waitStatus为0。
//唤醒头结点的下一结点(记为node1)后,node1继续进入自旋尝试获取资源。若成功获取则将首结点设置为自己,失败继续挂起。
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
- unparkSuccessor(Node node)
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
//设置结点waitStatus为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);
}