有限资源池中如何应用队列?

作者 : 开心源码 本文共2586个字,预计阅读时间需要7分钟 发布时间: 2022-05-12 共208人阅读

1. 什么是队列?

队列的特点是先进先出,有两个基本操作:入队(enqueue),放一个数据到队列尾部;出队(dequeue),从队列头部取一个元素。。它和栈一样,也是一种操作受限的线形表数据结构。

队列的应用非常广泛,特别是少量具备某些额外特性的队列,比方循环队列、阻塞队列、并发队列。它们在很多偏底层系统、框架、中间件的开发中,起着关键性的作用。

2. 如何实现队列?

跟栈一样,队列可以用数组来实现,也可以用链表来实现。用数组实现的队列叫作顺序队列,用链表实现的队列叫作链式队列

使用数组实现的队列:

public class QueueByArray<E> {    private int size;    private E[] data;    private int head;    private int tail;    public QueueByArray() {        this(8);    }    public QueueByArray(int size) {        data = (E[]) new Object[size];        this.size = size;    }    /**     * 入队     *     * @param element     * @return     */    public boolean enqueue(E element) {        // 队尾没有空间        if (tail == size) {            // 队列已满            if (head == 0) {                return false;            }            System.out.println("move element, head " + head + ", tail " + tail);            // 移动元素,从尾部向首部搬移            for (int i = head; i < tail; i++) {                data[i - head] = data[i];            }            tail -= head;            head = 0;        }        data[tail++] = element;        return true;    }    /**     * 出队     *     * @return     */    public E dequeue() {        // 队列为空        if (head == tail) {            return null;        }        return data[head++];    }}

使用链表实现的队列:

public class QueueByLink<E> {    private int size;    private Node head;    private Node tail;    /**     * 入队     *     * @param element     */    public void enqueue(E element) {        if (head == null) {            head = new Node();            head.element = element;            tail = head;        } else {            Node node = new Node();            node.element = element;            tail.next = node;            tail = node;        }        size++;    }    /**     * 出队     *     * @return     */    public E dequeue() {        if (head == null) {            return null;        }        E element = head.element;        head = head.next;        size--;        return element;    }    private class Node {        private E element;        private Node next;    }}

3. 循环队列

循环队列像一个环,首尾相连,避免了数据移动。实现循环队列的关键是,确定好队空和队满的判定条件。当队满时,(tail+1)%n=head

下面是使用数组实现循环队列:

public class CircularQueue<E> {    // 容量    private int size;    private E[] data;    private int head;    private int tail;    public CircularQueue() {        this(8);    }    public CircularQueue(int size) {        data = (E[]) new Object[size];        this.size = size;    }    /**     * 入队     *     * @param element     * @return     */    public boolean enqueue(E element) {        // 队列已满        if ((tail + 1) % size == head) {            return false;        }        data[tail] = element;        tail = (tail + 1) % size;        return true;    }    /**     * 出队     *     * @return     */    public E dequeue() {        // 队列为空        if (head == tail) {            return null;        }        E ele = data[head];        head = (head + 1) % size;        return ele;    }}

4. 阻塞队列和并发队列

阻塞队列就是在队列基础上添加了阻塞操作。简单来说,就是在队列为空的时候,从队头取数据会被阻塞。直到队列中有了数据才能返回;假如队列已经满了,那么插入数据就会被阻塞,直到队列中有空闲位置后再插入数据,而后再返回。这种基于阻塞队列实现的“生产者 – 消费者模型”,可以有效地协调生产和消费的速度。

线程安全的队列我们叫作并发队列。最简单直接的实现方式是直接在 enqueue()、dequeue() 方法上加锁,但是锁粒度大并发度会比较低,同一时刻仅允许一个存或者者取操作。实际上,基于数组的循环队列,利用 CAS 原子操作,可以实现非常高效的并发队列。这也是循环队列比链式队列应用更加广泛的起因。

线程池的阻塞队列分为两种:基于链表的实现方式,可以实现一个支持无限排队的无界队列,但是可能会导致过多的请求排队等待,请求解决的响应时间过长。而基于数组实现的有界队列,队列的大小有限,所以线程池中排队的请求超过队列大小时,接下来的请求就会被拒绝,设置一个正当的队列大小非常有讲究。

课后思考

还有哪些相似线程池结构或者者场景中会用到队列的排队请求呢?

自己是从事了七年开发的Android工程师,不少人私下问我,2019年Android进阶该怎样学,方法有没有?

没错,年初我花了一个多月的时间整理出来的学习资料,希望能帮助那些想进阶提升Android开发,却又不知道怎样进阶学习的朋友。【包括高级UI、性能优化、架构师课程、NDK、Kotlin、混合式开发(ReactNative+Weex)、Flutter等架构技术资料】,希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

资料获取方式:加入Android架构交流QQ群聊:513088520 ,进群即领取资料!!!

点击链接加入群聊【Android移动架构总群】:加入群聊

资料大全

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 有限资源池中如何应用队列?

发表回复