admin管理员组文章数量:1579083
2023年12月13日发(作者:)
AbstractQueuedSynchronizer::acquire源码笔记
此处的acquire方法指AQS内部的私有acquire方法,方法签名为
final int acquire(Node node, int arg, boolean shared,
boolean interruptible, boolean timed, long time)
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
// 此方法为私有的acquire方法,所有暴露出去的acquire方法最终都会使用不同的参数组合调用此方法
final int acquire(Node node, int arg, boolean shared,
boolean interruptible, boolean timed, long time) {
Thread current = tThread();
byte spins = 0, postSpins = 0; // retries upon unpark of first thread
boolean interrupted = false, first = false;
Node pred = null; // predecessor of node when enqueued
/*
* Repeatedly:
* Check if node now first
* if so, ensure head stable, else ensure valid predecessor
* if node is first or not yet enqueued, try acquiring
* else if node not yet created, create it
* else if not yet enqueued, try once to enqueue
* else if woken from park, retry (up to postSpins times)
* else if WAITING status not set, set and retry
* else park and clear WAITING status, and check cancellation
*/
for (;;) {
// 3个判断条件
// 1.此节点当前不是首节点
// 2.此节点前驱节点不为null
// 3.此节点前驱节点不是头结点,注意头结点跟首节点不是一个概念
if (!first && (pred = (node == null) ? null : ) != null &&
!(first = (head == pred))) {
// <0 说明前驱节点已经被取消,此时做一次等待队列清理
if ( < 0) {
cleanQueue(); // predecessor cancelled
continue;
// 如果此节点的前驱节点的前驱节点为null,则直接跳到下一次循环
// Wait(); 可方便虚拟机优化自选等待的过程,本身不包含额外的逻辑
} else if ( == null) {
Wait(); // ensure serialization
continue;
}
}
// 两个并列条件
// 1.当前节点是首节点
// 2.当前节点前驱节点未null,说明当前节点还未入队
// 只有这里的逻辑用到了tryAcquire,说明已经入队的非首节点是不能获取锁的
if (first || pred == null) {
boolean acquired;
// 基于是否为共享获取模式分别调用tryAcquireShared与tryAcquire
// 这两个方法都是无实现方法,需要用户自己实现其语义
try {
if (shared)
acquired = (tryAcquireShared(arg) >= 0);
else
acquired = tryAcquire(arg);
} catch (Throwable ex) {
cancelAcquire(node, interrupted, false);
throw ex;
}
// acquired == true 说明获取锁成功
if (acquired) {
// first == true 说明当前节点为首节点
// 需要将它出队并通知后继节点,这里采用的出队方式是将前导节点删除,将此节点数据清零作为新的头结点
if (first) {
= null;
head = node;
= null;
= null;
// 如果是共享锁,通知后继节点
if (shared)
signalNextIfShared(node);
if (interrupted)
upt();
}
return 1;
}
}
// 走到这里 node == null 说明未获取到锁并且node尚未建立(一个新线程第一次获取锁会出现这种情况)
// 发现这种情况,建立新的node然后重试,新建立的node还没有入队,所以其中的数据是什么无所谓,程序因此选择建立空node
if (node == null) { // allocate; retry before enqueue
if (shared)
node = new SharedNode();
else
node = new ExclusiveNode();
// 走到这里,说明node已经建立但是并未入队,且获取锁失败
// 这种情况下,将node入队然后再次进行尝试
} else if (pred == null) { // try to enqueue
= current;
Node t = tail;
vRelaxed(t); // avoid unnecessary fence if (t == null)
tryInitializeHead();
else if (!casTail(t, node))
vRelaxed(null); // back out
else
= node;
// 当前节点为首节点且自旋倒计时spin!=0
// 此时说明该节点被上一个节点唤醒成为首节点,而且自旋时间还未走完
} else if (first && spins != 0) {
--spins; // reduce unfairness on rewaits
Wait();
// 未获取到锁,且当前node状态为0(未定义)
// 此时node有两种情况,1-第一次入队获取锁失败走到这里; 2-状态为WAITING的情况下获取锁失败被park,然后被前驱节点唤醒,唤醒之后一定为首节点,其状态被复位,然后自旋时间走完来到这里
} else if ( == 0) {
= WAITING; // enable signal and recheck
} else {
long nanos;
// (postSpins << 1) | 1 等价于 postSpins*2+1
spins = postSpins = (byte)((postSpins << 1) | 1);
// 有时间限制的park和无时间限制的park
if (!timed)
(this);
else if ((nanos = time - me()) > 0L)
nos(this, nanos);
else
break;
// 走到这里说明线程从park状态被唤醒
tatus();
if ((interrupted |= upted()) && interruptible)
break;
}
}
return cancelAcquire(node, interrupted, interruptible);
}
版权声明:本文标题:AbstractQueuedSynchronizer::acquire源码笔记 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1702479590a9184.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论