Java-concurrency
Java-concurrency copied to clipboard
关于AbstractQueuedSynchronizer类中enq方法并没有让tail指向新的尾节点的两个疑问
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
//1. 构造头结点
if (compareAndSetHead(new Node()))
tail = head;
} else {
// 2. 尾插入,CAS操作失败自旋尝试
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
以上为enq()方法。 当队列为null时进入的enq方法,那 第一次循环是创建了头结点并且head,tail都指向此头结点。 那第二次循环是将参数node加入该头结点之后,形成第一个节点。但是为啥代码中tail没有更新呢?(意思就是现在tail,head,t都是指向"头结点")
自己的猜测:是否是在compareAndSetTail(t, node)中更新了tail值。
第二个问题是为什么返回t而不是tail?毕竟不管上面的假设成立不成立,t都指向新插入节点的前一个节点,而不是新节点。
第一个问题
compareAndSetTail代码如下:
private final boolean compareAndSetTail(Node expect, Node update) { return unsafe.compareAndSwapObject(this, tailOffset, expect, update); }
tailOffset就是tail域在AQS对象里的偏移量,用CAS更新尾结点。第一个不用猜测,点进去看看就知道了
第二个问题
从设计上我实在讲不出什么,只能说返回tail没什么意义,可以从以下几点理解
- enq(node)可以简单地理解为插入吧?CAS操作成功后,node即tail,你传了一个node,返回一个一样的node有什么意义呢?
- 看transferForSignal(node),它的作用是唤醒node结点,根据AQS的规定,需要将前一个结点,即node.prev设置成SIGNAL状态。这部分看Condition部分
:) 我也是最近才开始看并发的内容,感觉能有人一起讨论问题还是挺好的,你可以加我QQ:624684849 ,一起讨论问题