非阻塞链表 一行代码不理解
使用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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
留个坑,坐看大神回答