前言
AbstractQueuedSynchronizer是Java提供的用于同步的框架,采用了模版方法的设计模式,JUC下多个支持并发的工具例如Semaphore、ReentrantLock都在有内部类实现。
acquire
该方法会调用子类实现的tryAcquire ,子类实现tryAcquire用于判断是否获取到资源。
基本的流程一句话阐述就是
tryAcquire尝试获取资源,失败则通过自旋CAS方式加入同步队列,调用park等待其他线程执行unpark来唤醒
acquire方法源码如下:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
//addWaiter生成Node加入同步队列(通过自旋CAS)
//挂起等到其他线程唤醒head节点的后继节点
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
addWaiter方法源码如下:
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
//node前驱节点设置为 尾节点 (首次添加时head,后继为前驱节点)
node.prev = pred;
//把尾节点(tail)设置为node
if (compareAndSetTail(pred, node)) {
// 尾节点的next是自身
pred.next = node;
return node;
}
}
//尾节点(tail)设置node 失败
enq(node);
return node;
}
private Node enq(final Node node) {
//自旋CAS
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
//尾节点为空 初始化
if (compareAndSetHead(new Node()))
//尾节点 设置为 头节点
//头节点始终是空Node
tail = head;
} else {
//node前驱节点设置为 尾节点 (首次添加时时head,后续为前驱节点)
node.prev = t;
//把尾节点(tail)设置node
if (compareAndSetTail(t, node)) {
// 尾节点的next是自身
t.next = node;
return t;
}
}
}
}
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; // help GC
failed = false;
return interrupted;
}
// 获取资源失败时,判断是否需要进入等待
// 调用LockSupport.part 进入等待
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//parkAndCheckInterrupt 返回true 说明线程中断
interrupted = true;
}
} finally {
if (failed)
//tryAcquire执行报错会走这里
cancelAcquire(node);
}
}
shouldParkAfterFailedAcquire方法源码如下:
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
//前驱节点的waitStatus为 SIGNAL,表明当前节点需要被唤醒,该节点可以安全地进入等待状态
return true;
if (ws > 0) {
//Node.CANCELED = 1 ,ws>0 只有 这一个状态
//该节点的前驱节点已经被取消,循环继续向前驱搜索
//跳过前驱节点中所有被取消的节点
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//这是需要返回false,让外层代码再次tryAcquire,最后是确保无法获取资源后才进入等待
//同时 前驱节点的waitStatus设置为 SIGNAL 表明当前节点需要被唤醒
//release方法中,唤醒head节点的后继节点时,会把waitStatus设置为0,这时就会再次来到这里
//这样就避免出现:在当前节点进入等待前,被其他线程先执行唤醒
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
release
该方法会调用子类实现的tryRelease ,子类实现tryRelease用于判断是否释放资源
一句话阐述
tryRelease尝试释放资源,成功则调用unpark唤醒head节点的后继节点
release方法源码如下:
public final boolean release(int arg) {
//尝试释放资源
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
//调用LockSupport.unpark 唤醒head节点的后继节点
unparkSuccessor(h);
return true;
}
return false;
}
unparkSuccessor方法源码如下:
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
//当前节点waitStatus从Node.SIGNAL改为 0,触发后继节点进入等待前再次去执行tryAcquire (参见shouldParkAfterFailedAcquire方法)
compareAndSetWaitStatus(node, ws, 0);//Node waitStatus初始值
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);
}
魏王代序