Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于AbstractQueuedSynchronizer类中enq方法并没有让tail指向新的尾节点的两个疑问 #2

Open
MikasaLee opened this issue May 16, 2018 · 1 comment

Comments

@MikasaLee
Copy link

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都指向新插入节点的前一个节点,而不是新节点。

@CoDeleven
Copy link

第一个问题

compareAndSetTail代码如下:
private final boolean compareAndSetTail(Node expect, Node update) { return unsafe.compareAndSwapObject(this, tailOffset, expect, update); }
tailOffset就是tail域在AQS对象里的偏移量,用CAS更新尾结点。第一个不用猜测,点进去看看就知道了

第二个问题

从设计上我实在讲不出什么,只能说返回tail没什么意义,可以从以下几点理解

  1. enq(node)可以简单地理解为插入吧?CAS操作成功后,node即tail,你传了一个node,返回一个一样的node有什么意义呢?
  2. 看transferForSignal(node),它的作用是唤醒node结点,根据AQS的规定,需要将前一个结点,即node.prev设置成SIGNAL状态。这部分看Condition部分

:) 我也是最近才开始看并发的内容,感觉能有人一起讨论问题还是挺好的,你可以加我QQ:624684849 ,一起讨论问题

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants