实践中的Java并发性”;清单15.7。在Michael Scott非阻塞队列算法中插入(Michael和Scott,1996)。”;

实践中的Java并发性”;清单15.7。在Michael Scott非阻塞队列算法中插入(Michael和Scott,1996)。”;,java,multithreading,nonblocking,compare-and-swap,Java,Multithreading,Nonblocking,Compare And Swap,我正在阅读Java并发的实践和遭遇 package net.jcip.examples; 导入java.util.concurrent.atomic.*; 导入net.jcip.annotations.*; /** *链接队列 * *Michael Scott非阻塞队列算法中的插入 * *@作者Brian Goetz和Tim Peierls */ @线程安全 公共类链接队列{ 私有静态类节点{ 最后E项; 最后的原子参考; 公共节点(E项,LinkedQueue.Node下一个){ this.i

我正在阅读Java并发的实践和遭遇

package net.jcip.examples;
导入java.util.concurrent.atomic.*;
导入net.jcip.annotations.*;
/**
*链接队列
*

*Michael Scott非阻塞队列算法中的插入 * *@作者Brian Goetz和Tim Peierls */ @线程安全 公共类链接队列{ 私有静态类节点{ 最后E项; 最后的原子参考; 公共节点(E项,LinkedQueue.Node下一个){ this.item=项目; this.next=新原子参考(next); } } private final LinkedQueue.Node dummy=new LinkedQueue.Node(null,null); 私人最终原子参考头 =新原子参考(虚拟); 私有最终原子参考尾 =新原子参考(虚拟); 公共布尔put(E项){ LinkedQueue.Node newNode=newlinkedqueue.Node(项,null); while(true){ LinkedQueue.Node curTail=tail.get(); LinkedQueue.Node tailNext=curTail.next.get(); 如果(curTail==tail.get()){//此检查的目的是什么? if(tailNext!=null){ //队列处于中间状态,前进尾 tail.compareAndSet(缩减、tailNext); }否则{ //在静态状态下,尝试插入新节点 if(curTail.next.compareAndSet(null,newNode)){ //插入成功,请尝试推进尾部 tail.compareAndSet(缩减、新节点); 返回true; } } } } } }

如果我们有
If(curTail==tail.get())
检查,我们可以发现
tail
LinkedQueue.Node curTail=tail.get()之后是否已更改
,如果
尾部
已更改,请在循环时执行
。但是如果我们省略了这个检查并且
tail
LinkedQueue.Node curTail=tail.get()之后发生了更改,我们将在
tail.compareAndSet(curTail,tailNext)中失败
curTail.next.compareAndSet(null,newNode)
,我们将在执行
的同时
再次循环,,因此结果与检查结果相同


那么,有没有这张支票还有其他区别?我们可以省略这个检查吗?

这个差异看起来是第二个参数-我可以想象,compareAndSet with
tailNext
与调用下一个元素的compareAndSet with a read builded
newNode
有很大的不同。@Mike'Pomax'Kamermans但是如果
tail
发生了变化,两个
compareAndSet
s都将返回false。@JasonLaw
compareAndSet
将返回false,但它将继续循环直到false。进行此检查看起来很快就会失败。一旦
currTail
不是真正的tail,下面是useless@Tttttsing快速失败是我能想到的唯一原因。
package net.jcip.examples;

import java.util.concurrent.atomic.*;

import net.jcip.annotations.*;

/**
 * LinkedQueue
 * <p/>
 * Insertion in the Michael-Scott nonblocking queue algorithm
 *
 * @author Brian Goetz and Tim Peierls
 */
@ThreadSafe
public class LinkedQueue <E> {

    private static class Node <E> {
        final E item;
        final AtomicReference<LinkedQueue.Node<E>> next;

        public Node(E item, LinkedQueue.Node<E> next) {
            this.item = item;
            this.next = new AtomicReference<LinkedQueue.Node<E>>(next);
        }
    }

    private final LinkedQueue.Node<E> dummy = new LinkedQueue.Node<E>(null, null);
    private final AtomicReference<LinkedQueue.Node<E>> head
            = new AtomicReference<LinkedQueue.Node<E>>(dummy);
    private final AtomicReference<LinkedQueue.Node<E>> tail
            = new AtomicReference<LinkedQueue.Node<E>>(dummy);

    public boolean put(E item) {
        LinkedQueue.Node<E> newNode = new LinkedQueue.Node<E>(item, null);
        while (true) {
            LinkedQueue.Node<E> curTail = tail.get();
            LinkedQueue.Node<E> tailNext = curTail.next.get();
            if (curTail == tail.get()) { // what is the purpose of this check?
                if (tailNext != null) {
                    // Queue in intermediate state, advance tail
                    tail.compareAndSet(curTail, tailNext);
                } else {
                    // In quiescent state, try inserting new node
                    if (curTail.next.compareAndSet(null, newNode)) {
                        // Insertion succeeded, try advancing tail
                        tail.compareAndSet(curTail, newNode);
                        return true;
                    }
                }
            }
        }
    }
}