shouldParkAfterFailedAcquire
获取同步状态失败后应该停放
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
//前驱节点状态
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
//前驱节点状态是SIGNAL 说明前驱释放同步状态回来唤醒 直接返回
return true;
if (ws > 0) {
//如果前驱状态大于0 说明被取消了,就一直往前找,找到没被取消的节点
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
//排在没被取消的节点后面
pred.next = node;
} else {
//前驱没被取消,而且状态不是SIGNAL CAS将状态更新为SIGNAL,释放同步状态要来唤醒
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
实际上是park前的一些准备
再来看看 parkAndCheckInterrupt
,用工具类进入等待状态,被唤醒后检查是否中断
private final boolean parkAndCheckInterrupt() {
//线程进入等待状态...
LockSupport.park(this);
//检查是否中断 (会清除中断标记位)
return Thread.interrupted();
}
在acquireQueued
的中如果未获取同步状态并且抛出异常,最终会执行cancelAcquire
取消
当感知到中断时返回true回去,来到第一层acquire
方法执行selfInterrupt
方法,自己中断线程
acquire流程图:
- 先尝试获取同步状态失败则CAS+失败重试添加到AQS末尾
- 前驱节点为头节点且获取同步状态成功则返回,否则进入等待状态等待唤醒,唤醒后重试
- 在2期间发生异常取消当前节点
释放同步状态
先进行释放同步状态,成功后头节点状态不为0 唤醒下一个状态不是被取消的节点
public final boolean release(int arg) {
//释放同步状态
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
//唤醒下一个状态不大于0(大于0就是取消)的节点
unparkSuccessor(h);
return true;
}
return false;
}
响应中断
acquireInterruptibly
用于响应中断的获取同步状态
public final void acquireInterruptibly(int arg)
throws InterruptedException {
//查看是否被中断,中断抛出异常
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
doAcquireInterruptibly
与原过程类似,就是在被唤醒后检查到被中断时抛出中断异常
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
&nbs