concurrentLinkedList中的这段代码是什么意思?

    public boolean offer(E e) {
        checkNotNull(e);
        final Node<E> newNode = new Node<E>(e);

        for (Node<E> t = tail, p = t;;) {
            Node<E> q = p.next;
            if (q == null) {
                // p is last node
                if (p.casNext(null, newNode)) {
                    // Successful CAS is the linearization point
                    // for e to become an element of this queue,
                    // and for newNode to become "live".
                    if (p != t) // hop two nodes at a time
                        casTail(t, newNode);  // Failure is OK.
                    return true;
                }
                // Lost CAS race to another thread; re-read next
            }
            else if (p == q)
                // We have fallen off list.  If tail is unchanged, it
                // will also be off-list, in which case we need to
                // jump to head, from which all live nodes are always
                // reachable.  Else the new tail is a better bet.
                p = (t != (t = tail)) ? t : head;
            else
                // Check for tail updates after two hops.
                p = (p != t && t != (t = tail)) ? t : q;
        }
    }

我对最后的p = (t != (t = tail)) ? t : head 有些没太看明白,按照执行顺序,先执行括号内的t= tail,然后比较t != t,那不就是始终为true了吗?请问是我哪里理解有问题呢?

阅读 3.4k
1 个回答

这个就是看(t != (t = tail))这句话怎么执行的了。
简化一下,看下面代码:

int i = 0;
int j = 1;
if(i != (i = j)) {
    System.out.println(i);
}

这个代码,跟你的代码意思一样的,这样简化比较好理解。
对这个代码的class文件进行反编译,查看其字节码

0: iconst_0
1: istore_1
2: iconst_1
3: istore_2
4: iload_1
5: iload_2
6: dup
7: istore_1
8: if_icmpeq     18
11: getstatic     #2 // Field java/lang/System.out:Ljava/io/PrintStream;
14: iload_1
15: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
18: return

主要的就在第0-8行,逐行分析一下:

0: iconst_0 // 0入栈,此时栈[0]
1: istore_1 // 栈顶弹出,赋值给【变量1】(即i),此时i值为0,栈[]
2: iconst_1 // 1入栈,此时栈[1]
3: istore_2 // 栈顶弹出,赋值给【变量2】(即j),此时j值为1,栈[]
4: iload_1 // 【局部变量1】(即i)的值入栈,此时栈[0]
5: iload_2 // 【局部变量2】(即j)的值入栈,此时栈[0, 1]
6: dup      // 复制栈顶的值(即1),将其入栈,此时栈[0, 1, 1]
7: istore_1 // 栈顶弹出,赋值给【变量1】(即i),此时i值为1,栈[0, 1]
8: if_icmpeq     18 // 栈顶弹出两个元素(即1,0),进行比较,如果相等,跳转到18行,就是return。很明显,这里不相等,所以会继续往下走,即调用System.out.println打印。此时栈[]

可以看出,确实在发生比较之前,变量i的值已经改变了,但是栈内的元素还是旧值,所以比较还是采用旧值进行比较。

同样的道理,只不过你的代码,会改变一些指令,但是基本原理还是这样的。
你的代码比较其实就是比较ttail,而不是赋值之后的t

这段代码的意图就是,在当前线程执行这段代码期间,其他线程执行了其他操作,导致链表的尾部对象发生了变化,这个时候重新遍历链表,来重新确定要offer的这个对象的位置。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题