ConcurrentLinkedQueue 出入队源码分析(java 并发编程的艺术6.2章)

6.2 ConcurrentLinkedQueue

 

一个基于链接节点的无界线程安全队列

 

6.2.2 入队列

 

1、入队列的过程

1、添加元素1,队列更新head节点的next节点为元素1节点,tail节点默认情况下等于head节点

2、添加元素2,队列首先设置元素1节点的next节点为元素2节点,然后更新tail节点指向元素2节点

3、添加元素3,设置tail节点的next节点为元素3节点

4、添加元素4,设置元素3的next节点为元素4节点,然后将tail节点指向元素4节点

 

看下offer的例子

public boolean offer(E e) {

    checkNotNull(e);

    final Node<E> newNode = new Node<E>(e);



    for (Node<E> t = tail, p = t;;) {

        Node<E> q = p.next;                  // 步骤1

        if (q == null) {                     

            // p is last node

            if (p.casNext(null, newNode)) {      //步骤2

                // Successful CAS is the linearization point

                // for e to become an element of this queue,

                // and for newNode to become "live".

                if (p != t) // hop two nodes at a time

                    casTail(t, newNode);  // Failure is OK.     //步骤5

                return true;

            }

            // Lost CAS race to another thread; re-read next

        }

        else if (p == q)                        

            // We have fallen off list.  If tail is unchanged, it

            // will also be off-list, in which case we need to

            // jump to head, from which all live nodes are always

            // reachable.  Else the new tail is a better bet.

            p = (t != (t = tail)) ? t : head;     //步骤3

        else                                

            // Check for tail updates after two hops.

            p = (p != t && t != (t = tail)) ? t : q;        //步骤4

    }

}

 

为了方便理解这里用图来表示下 添加俩个元素的情况下,队列的变化情况 ( 每个步骤相应的源码在上面的源码块有标注,对照看)

 

 

    

 

根据以上代码可以看出,添加2次元素才会设置一次tail节点,从本质上来看通过增加对volatile变量的读操作来减少对volatile变量的写操作,所以入队效率会有所提升

 

6.2.3 出队列

 

 

要注意 不是每次弹出首节点都需要更新head,只有当head节点里面没有数据了才会去更新,减少CAS的使用

public E poll() {

    restartFromHead:

    for (;;) {

        for (Node<E> h = head, p = h, q;;) {

            E item = p.item;



            if (item != null && p.casItem(item, null)) {                 //步骤1

                // Successful CAS is the linearization point

                // for item to be removed from this queue.

                if (p != h) // hop two nodes at a time

                    updateHead(h, ((q = p.next) != null) ? q : p);       //步骤4

                return item;

            }

            else if ((q = p.next) == null) {                            

                updateHead(h, p);                                        //步骤2

                return null;

            }

            else if (p == q)

                continue restartFromHead;                                

            else

                p = q;                                                   //步骤三

        }

    }

}

 

下面用图来表示下 源码的逻辑( 每个步骤相应的源码在上面的源码块有标注,对照看)

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值