上一节的acquireQueued(addWaiter(Node.EXCLUSIVE), arg))函数中有一个addWaiter函数,表示将当前线程加入到排队队列中
//这个函数比较简单,就是将node放到队列末尾,mode表示是独占锁还是共享锁以后再讨论
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) {//如果tail不是null,表示队列已被初始化则将node 放到队尾
node.prev = pred;
if (compareAndSetTail(pred, node)) {//cas将tail指向node,如果cas失败表示有多个线程都要放到队尾,这个时候会走到enq函数,该还是会再去cas放到队尾
pred.next = node;
return node;
}
}
enq(node); //初始化队列或者再次cas队尾
return node;
}
//该函数会初始化队列(如果队列未被初始化)
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize 初始化队列
if (compareAndSetHead(new Node())) //将head设置为一个空node。这个空node很重要,aqs的队头一定是空节点,用来表示正在执行的那个线程,想一下当执行线程结束后只有这个空节点才能去唤醒下一个节点,假如队头节点就是等待线程,谁能去唤醒他呢
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {//cas队尾,如果还失败看到这个是死循环会一直去放,直到放到队尾为止
t.next = node;
return t;
}
}
}
}
读完这2个函数有个疑问,是不是可以直接缩减成1个函数,addWaiter中cas那段和enq是一样的。
网友评论