基于CAS的非阻塞同步队列的实现

基于CAS实现的组件有很多,这里选择非阻塞同步队列的原因是,当有多个线程同时添加元素时,在队列的尾部如何利用cas保证两个操作的原子性是有相应算法的(这两个步骤是尾节点需要指向新增的元素,最后一个节点元素需要指向新增的元素,即新增的元素必须同时有这两个节点指向它)。代码如下:

public class ConcurentQueue {

    static class Node {
        public Object e;
        public AtomicReference<Node> nextRef ;

        public Node(Object e,Node next) {
            super();
            this.e = e;
            this.nextRef = new AtomicReference<Node>(next);
        }
    }
    private Node head = new Node(null,null);
    private Node tail = new Node(null,head);

    public void add(Object e) {
        Node new_node = new Node(e,null);//待插入节点
        while(true){
            Node curLast = tail.nextRef.get();//当前最后节点
            Node next = curLast.nextRef.get();//当前最后节点的next节点
            if(next != null){//A 如果当前最后节点的next节点不为空,说明尾节点需要指向next节点
                tail.nextRef.compareAndSet(curLast, next);
            }else{
                if(curLast.nextRef.compareAndSet(null, new_node)){//* B 将当前最后节点的next节点设置为新插入的节点
                    tail.nextRef.compareAndSet(curLast, new_node);//* C  将尾节点的next节点设置为新插入的节点
                    return;
                }
            }
        }
        
    }

    

   public Object remove() {
        while (true) {
            Node next = head.nextRef.get();
            if (next == null) {
                return null;
            } else {
                Node nextSetNode = next.nextRef.get();
                if (head.nextRef.compareAndSet(next, nextSetNode)) {
                    return next.e;
                }
            }
        }
    }
}

打*的两个地方原本是需要同时成功才能保证正确性的,但根据现在了解的是cas只能保证一个操作的原子性,若要保证两个操作的原子性,初看是不可能的。细心的朋友可以看出这些代码和java并发编程实战中的是几乎一样的,也只有将head节点也作为哑节点这一小小改动,(注意尾节点和最后一个节点是不同的节点),首先队列永远只有两种状态,见书中的原图(不过描述得改成中间态和稳定态):

295daac4be4c1047918e67816f88e15d029.jpg

其次队列永远只能在最后一个节点后面即稳定态的时候才能插入!

先分析一下代码:

1、当B步骤成功后,还没来得及执行C步骤前,此时队列就处于中间态,其余线程就会执行A步骤将尾节点推到最后一个节点上从而形成稳定态,此时再执行C步骤时尽管失败了但是队列已经稳定;

2、只要队列不稳定时,所有的线程都会设法执行A步骤将队列趋于稳定;

3、C步骤不管是成功还是失败队列都会处于稳定状态;

到这里大家可以去体会一下java并发编程实战中说的:那两个技巧了,说实在的没看懂代码前能看懂那些话么....,还有能想到这种方法确实不容易,想想还是用锁实现比较简单明了。

 

 

转载于:https://my.oschina.net/u/1268334/blog/3035181

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值