关于AQS中enq( )方法CAS操作的疑惑

时间:2022-12-13 18:57:08
private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            //如果队列为空则新建头结点
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    //将tail指向头结点
                    tail = head;
            } else {
            	//1.将新节点的前置指针指向链表尾部
                node.prev = t;
                //2.通过CAS将tail的引用指向node
                if (compareAndSetTail(t, node)) {
                    //3.将原尾部节点的后置指针指向新节点
                    t.next = node;
                    //for循环的出口
                    return t;
                }
            }
        }
    }

这是节点进入同步队列的方法,其中的CAS操作compareAndSetTail(t, node),作用为将tail的引用指向node,参数t中的内容是tail的旧引用对象地址,node是新节点的地址。再来看看AQS中compareAndSetTail(t, node)具体内容,

private final boolean compareAndSetTail(Node expect, Node update) {
        return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
    }
tailOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));

这里的tailOffset,是通过unsafe类中的方法获取到的是“tail”变量相对于Java对象的“起始地址”的偏移量,即tailOffset可以理解为tail的地址。也就是说这里CAS操作更新的知识tail变量的地址上的数据,并不会对局部变量t上的值做修改,执行完compareAndSetTail(t, node)后,t还是指向原来的旧链尾,而tail指向了新的节点。