search

Home  >  Q&A  >  body text

java - AbstractQueuedSynchronizer中CAS的疑惑

这段代码是AQS框架中将当前节点入队的操作。

Node pred = tail;
if (pred != null) {
    node.prev = pred;
    if (compareAndSetTail(pred, node)) {
        pred.next = node;
        return node;
    }
}

上面代码中pred被赋值为尾节点,node为当前节点。我理解的将新节点插入链表尾处的逻辑应当如下:
node.prev = pred; node节点的前驱指向尾节点
pred.next = node; 将尾节点的后继设置为当前节点
tail = node; 将node节点设置为尾节点
对于上面代码我的疑问如下:
如果尾节点不为空,node节点的前驱会指向尾节点,然后调用CAS交换pred和node的值。
此时pred(即tail)的值应该已经是当前节点node的值了,再执行pred.next=node是什么意思呢,这是否存在逻辑问题?

巴扎黑巴扎黑2803 days ago677

reply all(2)I'll reply

  • ringa_lee

    ringa_lee2017-04-18 10:54:59

    TZ may have a wrong understanding of compareAndSetTail.

    private final boolean compareAndSetTail(Node expect, Node update) {
            return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
        }

    Compare the value of pred with the expected node value at the tailOffset position of AbstractQueuedSynchronizer. If they are the same, update the value of the tailOffset position.

    static {
        tailOffset = unsafe.objectFieldOffset
        (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
        ...
    }
    

    compareAndSetTail(pred, node) After the execution of this code is completed, only the value of tailOffset of the object AbstractQueuedSynchronizer is modified, that is, the value of the member variable tail, which has no effect on the value of pred. As for the doubly linked list, there is no logical problem with tail insertion.

    reply
    0
  • PHPz

    PHPz2017-04-18 10:54:59

    This design is a 双向链表.
    B.prev == A
    A.next == B

    compareAndSetTail 设置成功只是将 tail 更新为当前node. pred.next 是将上一个尾部节点的next设置为当前nodeThere is no problem with this logic.

    reply
    0
  • Cancelreply