AQS入队方法enq分析(发布日期:2021-02-21)
2021-02-21 本文已影响0人
watermountain
JDK版本:
1.8.0_171
方法:
java.util.concurrent.locks.AbstractQueuedSynchronizer#enq
/**
* 将节点插入队列,必要时进行初始化。
* Inserts node into queue, initializing if necessary. See picture above.
* @param node the node to insert 要插入的节点
* @return node's predecessor 前驱节点
*/
private Node enq(final Node node) {
for (;;) {
Node t = tail;
// t == null 等价于 tail == null
// compareAndSetHead 更新队列头
// tail = head 队列头、队列尾指向哑节点(dummy node)new Node()创建的节点
/**
* 初始化之后的队列
* <pre>
* +------+
* head --> | | <-- tail
* +------+
* </pre>
*/
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
// 初始化之后,入队节点
// 入队节点的前一个节点设置为tail节点
//
node.prev = t; // 设置插入节点node前驱节点
if (compareAndSetTail(t, node)) { // 将插入节点node设置为tail节点, compareAndSetTail只更新tail, t的引用(指向的对象不变)
t.next = node; // 插入节点node的前驱节点的下一个节点为要插入的节点node
return t; // 返回插入节点node的前驱节点
}
/**
* <pre>
* +------+ <-- +------+
* head --> | | | | <-- tail
* +------+ --> +------+
* 哑巴节点 要插入的节点node
* </pre>
*/
}
}
}
以给定模式(独占或共享)为当前线程创建(等待队列)节点,并将创建的节点加入等待队列
/**
* Creates and enqueues node for current thread and given mode.
*
* @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
* @return the new node
*/
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) { // 队列非空时
/**
* 队列非空时, 执行插入节点之前的逻辑
* <pre>
* +------+ <-- +------+
* head --> | | | | <-- tail
* +------+ --> +------+
* 哑巴节点 要插入的节点node
* </pre>
*/
node.prev = pred; // 插入节点node的前驱节点为尾节点
if (compareAndSetTail(pred, node)) { // 插入节点node设置为尾节点
pred.next = node; // 前驱节点的下一个节点为插入节点node
return node; // 返回插入节点node
}
}
/**
* <pre>
* +------+ <-- +------+ <-- +------+
* head --> | | | | | | <-- tail
* +------+ --> +------+ --> +------+
* 哑巴节点 要插入的节点node
* </pre>
*/
enq(node);
return node;
}
CAS 更新队列头节点、尾节点方法,仅入队时使用
/**
* CAS head field. Used only by enq.
*/
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
/**
* CAS tail field. Used only by enq.
*/
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
哑节点:
可以起到避免处理头节点为空的边界问题的作用,减少代码执行异常的可能性