ConcurrentLinkedQueue(并发队列)

JDK在1.5以后由Doug Lea为我们提供了ConcurrentLinkedQueue这个线程安全的队列。数据结构是链表的实现。这里我们通过分析java中的ConcurrentLinkedQueue的实现来理解并发队列。

结构定义

在ConcurrentLinkedQueue中,所有的记录通过其内部的Node结构进行包装。并维护着二个由volatile关键字修饰的队列头尾节点.head/tail.

//java中实现并发队列的实现

public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> implements Queue<E>, Serializable {

  //队列的头部节点.

  private transient volatile Node<E> head;

  //队列的尾部节点.队列中唯一一个node.next可以是null的节点.

  private transient volatile Node<E> tail;

   //初始化队列,生成head,tail的哨兵节点,他们的next都是null.

  public ConcurrentLinkedQueue() {

    head = tail = new Node<E>(null);

  }

  //队列存储记录的节点数据结构,基于CAS实现的线程安全.

  private static class Node<E> {

    volatile E item; //记录值

    volatile Node<E> next; //当前节点的下一节点指针

    //初始化

    Node(E item) {

        UNSAFE.putObject(this, itemOffset, item);

    }

    //更新节点值,

    boolean casItem(E cmp, E val) {

        return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);

    }

    //延时设置node的next指针,在更新表头时,让node.next指向node自己.

    void lazySetNext(Node<E> val) {

        UNSAFE.putOrderedObject(this, nextOffset, val);

    }

    //更新节点的next指针.

    boolean casNext(Node<E> cmp, Node<E> val) {

        return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);

    }

}

插入数据(offer)

在ConcurrentLinkedQueue并发队列的实现中插入操作通过CAS自旋来实现,向队列插入从队列的尾部tail开始,插入数据可以分为三种场景:单线程插入、多线程插入与多线程插入读取并行,在并发的场景下tail可能不是真实的尾节点,因此插入时要不断迭代来确保是在真实的尾节点后面插入数据(并发队列每插入两个节点更新一次tail)。

//并发队列的入队实现,这里有三种情况,单线程插入,多线程插入,多线程同时插入与读取

public boolean offer(E e) {

    //1,并发队列中的记录值不能是null.

    checkNotNull(e);

    //根据记录值生成队列中存储的节点.

    final Node<E> newNode = ne

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值