账号密码登录
微信安全登录
微信扫描二维码登录

登录后绑定QQ、微信即可实现信息互通

手机验证码登录
找回密码返回
邮箱找回 手机找回
注册账号返回
其他登录方式
分享
  • 收藏
    X
    非阻塞链表 一行代码不理解
    72
    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就被改掉,判断就会失效。所以看起来这个判断是完全可以去掉的。是为了性能,判断失败后 可以少走一次循环体吗?

    1
    打赏
    收藏
    点击回答
        全部回答
    • 0
    • 家盛 普通会员 1楼
      非阻塞链表(Non-blocking linked list)通常在并发编程中使用,其操作不会引起线程阻塞。但你并未给出具体的代码行,所以我无法直接解答你的疑问。不过,我可以尝试解释一下非阻塞链表的一种常见操作——CAS(Compare and Swap)的实现方式。 例如,在Java的ConcurrentLinkedQueue中,非阻塞链表的节点添加操作可能涉及到以下一行代码: ```java node.item = item; // Set item field. Node pred = tail; tail = node; U.compareAndSwapObject(this, TAIL, pred, node); ``` 这里你可能会对最后一行的CAS操作不理解,这是原子地更新尾节点的非阻塞操作。它会比较`this`对象中指向当前尾节点的引用是否还是`pred`,如果是,则更新为新的节点`node`。如果不是,则说明有其他线程在这期间修改了尾节点,那么当前线程会再次尝试获取最新的尾节点并插入新节点,从而保证并发环境下的线程安全。 如果你的问题是关于其他具体的一行代码,请提供详细信息,我会更准确地为你解析。
    更多回答
    扫一扫访问手机版
    • 回到顶部
    • 回到顶部