MpmcArrayQueue学习

前言

在netty的NioEventLoop中用到的jcTools下的MPSC队列很有必要学习下。由于MPSC队列是多生产单消费者的,MPMC是多生产者多消费者的,更有利于学习,故此篇以MpmcArrayQueue为基础。在学习之前,先简单回顾一遍队列及相关知识。

队列

队列是一种FIFO的数据结构,使用队列存取数据元素时,数据元素只能从表的一端进入队列,另一端出队列。常见于线程池的等待排队,锁的等待排队。
队列有两种实现方式(堆栈实现不讨论)

  • 顺序存储实现–>数组
  • 链式存储实现–>链表

Queue定义如下:

public interface Queue<E> {
   
    void enqueue(E e);
    E dequeue();
    int size();
}

定义了三个方法enqueue入队,dequeue出队,size队列大小。
基于数组实现的queue:

public class ArrayQueue1<E> implements Queue<E> {
   
    private Object[] elements;
    private int size;
    private int index;
    private int capacity;

    public ArrayQueue1(int capacity) {
   
        this.capacity = capacity;
        elements = new Object[capacity];
    }

    @Override
    public void enqueue(E e) {
   
        elements[index++] = e;
        size++;
    }

    @Override
    public E dequeue() {
   
        E e = (E) elements[0];
        moveLeftOneStep();
        index--;
        size--;
        return e;
    }

    //左移一步
    private void moveLeftOneStep() {
   
        for (int i = 1; i < elements.length - 1; i++) {
   
            elements[i] = elements[i + 1];
        }
    }

    @Override
    public int size() {
   
        return this.size;
    }

}

ArrayQueue1中队列通过给定一个容量进行初始化,Object数组用于存元素,index表示元素放到何处了,size表示元素的个数。入队的时候index处放元素,然后index自增1,size加1。出队的时候从头(0号位置)取,取完之后剩余的元素集体左移一步。
注:上述代码省略了边界条件校验等其它必要的校验。

ArrayQueue1的代码存在一个不好的地方:每取一次元素都要移动一次,有N个元素就要移动N-1次。如果用时间复杂度表示就是O(n),这显然是不可接受的。于是,有了第二种的数组实现队列:循环数组队列。

基于循环数组的队列

循环数组是一个如同环的数组,它用两个指针putIndex和takeIndex,移动takeIndex就可以指示出可以取的元素在哪儿,就可以不用再移动元素,如下图。
图1 容量为8的环形数组

这样做有两个问题需要考虑:

  • Q1:如何判断队列满或空?
  • Q2:数组是线性的,有限的,指针如何进行循环?

Q1的答案有3种。

  • A1:预留长度法
  • A2:预留一位法
  • A3:设标志位法

Q2的答案有2种。

  • A1:取余
  • A2:指针到达尾部置0

Q1的解决方法采用A1-预留长度法,入队+1,出队-1,size == capacity为满,size==0为空。Q2的解决方法采用A2来处理。
代码如下:

public class ArrayQueue2<E> implements Queue<E> {
   
    private Object[] elements;
    private int size;
    private int putIndex;
    private int takeIndex;

    public ArrayQueue2(int capacity) {
   
        this.elements = new Object[capacity];
    }

    @Override
    public void enqueue(
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值