实践中的Java并发性”;清单15.7。在Michael Scott非阻塞队列算法中插入(Michael和Scott,1996)。”;
我正在阅读Java并发的实践和遭遇实践中的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
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 withtailNext
与调用下一个元素的compareAndSet with a read buildednewNode
有很大的不同。@Mike'Pomax'Kamermans但是如果tail
发生了变化,两个compareAndSet
s都将返回false。@JasonLawcompareAndSet
将返回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;
}
}
}
}
}
}