JUC并发容器——ConcurrentLinkedQueue

线程安全的队列

  • 阻塞队列:使用一个锁(进队和出队同一个锁)和两个锁(入队和出队用不同的锁)
  • 非阻塞队列:ConcurrentLinkedQueue

ConcurrentLinkedQueue特性:

  1. 是一个基于链接节点的无界线程安全队列,
  2. 先进先出的插入顺序进行排序,
  3. 采用“wait-free”算法(CAS算法)实现,
  4. 具体实现:添加元素时它会添加到队列尾部;获取元素时,它会返回队列头部的元素。

1.8 source code

https://blog.csdn.net/chenssy/article/details/74853120
1、入队方法

public boolean offer(E e) {
    //判断入队节点是否为空
    checkNotNull(e);
    //构造入队节点
    final Node<E> newNode = new Node<E>(e);
    //死循环,入队不成功继续入队
    //p初始为tail
    for (Node<E> t = tail, p = t;;) {
        //q为p的后继,若p为队尾,则q为空,若p不是队尾,则有其他线程更改了队列
        Node<E> q = p.next;
        if (q == null) {
            //p是队尾  将入队节点变成队尾的后继
            if (p.casNext(null, newNode)) {
                //判断tail节点是否为尾节点
                if (p != t)
                    //如果不是,将入队节点修改为队尾
                    casTail(t, newNode);
                return true;
            }
            // Lost CAS race to another thread; re-read next
        }
        //说明这个节点已经被移除了
        else if (p == q)
            //如果队尾未发生改变,t还是队尾,则将p指向t,继续插入新节点
            //如果队尾发生改变,则将p指向队头重新开始插入新节点
            p = (t != (t = tail)) ? t : head;
        else
            //说明p有后继,p的后继才是队尾,则需要将p指向队尾
            p = (p != t && t != (t = tail)) ? t : q;
    }
}
入队方法个人感觉还是挺复杂的。大致步骤如下

1、构造新节点

2、开始循环,p表示队尾,默认p初始为tail,

3、如果p后继为空,说明p就是tail,则插入新节点返回

4、如果p节点被删除,则需要重新赋值p,如果tail未变,则将p赋值为t,如果tail改变,则将p赋值为队头,继续插入

5、如果p有后继,说明p不是tail,则需要将p指向tail。

2出队方法

public E poll() {
    restartFromHead:
    //死循环
    for (;;) {
        for (Node<E> h = head, p = h, q;;) {
            //取出队头的值
            E item = p.item;
            //如果队头值不为空则将队头的值更新为空
            if (item != null && p.casItem(item, null)) {
                //判断p是否等于head,如果不等于则重新指向队头
                if (p != h)
                    updateHead(h, ((q = p.next) != null) ? q : p);
                return item;
            }
            //队列为空
            else if ((q = p.next) == null) {
                updateHead(h, p);
                return null;
            }
            //有其他线程将队头的值出队了,则重新开始出队
            else if (p == q)
                continue restartFromHead;
            else
                p = q;
        }
    }
}
出队的大致步骤如下:

1、h等于head,p初始化为head

2、取出队头的值

3、如果队头的值不为空,则将队头的值置空,然后判断head是否变化,如果变化重新寻找head,返回队头的值

4、如果队列为空,则需要重新寻找队头,返回null

5、如果有其他线程将队头的值出队了,那么重新从最新head开始出队
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值