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指向了新的节点。