非阻塞链表 一行代码不理解

发布于 2022-09-06 08:42:59 字数 1844 浏览 26 评论 0

使用cas操作实现非阻塞链表 其中put方法 代码如下

public class LinkedQueue <E> {
    private static class Node <E> {
        final E item;
        final AtomicReference<Node<E>> next;
        Node(E item, Node<E> next) {
            this.item = item;
            this.next = new AtomicReference<Node<E>>(next);
        }
    }
    private AtomicReference<Node<E>> head
        = new AtomicReference<Node<E>>(new Node<E>(null, null));
    private AtomicReference<Node<E>> tail = head;
    public boolean put(E item) {
        Node<E> newNode = new Node<E>(item, null);
        while (true) {
            Node<E> curTail = tail.get();//1
            Node<E> residue = curTail.next.get();
            if (curTail == tail.get()) {//2
                if (residue == null) /* A */ {
                    if (curTail.next.compareAndSet(null, newNode)) /* C */ {
                        tail.compareAndSet(curTail, newNode) /* D */ ;
                        return true;
                    }
                } else {
                    tail.compareAndSet(curTail, residue) /* B */;
                }
            }
        }
    }
}

代码来源: developerworks文章《非阻塞算法简介》 非阻塞链表 章节

疑惑:这段代码的大体思路、原理 是理解的,但2处注释的代码,即if (curTail == tail.get())这行的判断不理解。这个判断是有必要的吗?可以去掉吗?为什么?

2处的curTail就是1处tail.get() 的结果。如果需要判断的话,应该是在并发情况下,1、2处分别调用tail.get()的返回的可能不是同一个对象。也就是说,2处判断的时候,tail可能被修改了。1到2处之间没有修改tail的动作,所以只能是别的一个线程修改了tail;只看这段代码的话,只能是别的线程调用put方法时执行了B或D。所以安插了这么一个判断。

但是有什么用呢?这是个“先判断后执行”的动作,但是因为非阻塞不加锁,[判断+执行]并没有被同步起来;所以,可能刚刚判断之后,tail就被改掉,判断就会失效。所以看起来这个判断是完全可以去掉的。是为了性能,判断失败后 可以少走一次循环体吗?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

灯角 2022-09-13 08:43:11

留个坑,坐看大神回答

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文