算法与数据结构(队列)

本文介绍了队列的基本概念和两种常见实现方式:顺序队列和链式队列,以及环形队列的优化。讨论了阻塞队列和并发队列,特别是并发队列如何利用数组和CAS实现高效并发。队列在固定线程池连接数场景中的应用也被提及,分析了无界队列和有界队列在响应时间和资源利用率上的考量。
摘要由CSDN通过智能技术生成

队列(queue):
 先进先出。
队列的2个基本操作
 1,入队:enqueue,放一个元素到队列尾部。
 2,出队:dequeue,从队列头部取一个元素。

实现队列的2种方式:
 1,顺序队列:用数组实现

    private String[] data;//存数据的数组
    private int size;//容量
    private int head = 0;//头部位置
    private int tail = 0;//尾部诶之

    public ArrayQueue(int capacity) {
        data = new String[capacity];
        size = capacity;
    }

    public Boolean enqueue(String param) {//入队操作优化,可以当队列满了在执行数据移动。
        if (tail == size) {
            if (head == 0) {
                return false;
            } else {
                for (int i = 0; i < tail - head; i++) {//数组满了,移动有效数据,清理无效数据。
                    data[i] = data[head + i];
                    data[head + i] = null;
                }
                tail = tail - head;
                head = 0;
            }
        }
        data[tail] = param;
        tail++;
        return true;
    }

    public String dequeue() {

if (data[head] == null) {
            return null;
        }
        String ret = data[head];
        data[head] = null;
        head++;
        return ret;
    }

 2,链式队列:用链表实现(后续实现)。


 环形队列:

    private String[] data;
    private int size;
    private int head = 0;
    private int tail = 0;

    public CircleQueue(int capacity) {
        data = new String[capacity];
        size = capacity;
    }

    public Boolean enqueue(String param) {

        if (tail != 0 && tail%size == head) {//数据不为空并且尾部+1取余等于头部时,数据满了
            return false;
        }
        if (tail == size) {//尾部等于最大容量时,环形结构,从0开始
            tail = 0;
        }

        data[tail] = param;
        tail++;
        return true;
    }

    public String dequeue() {
        if (data[head]== null) {
            return null;
        }
        String ret = data[head];
        data[head] = null;
        head++;
        head %= size;防止头部位置大于数组容量
        return ret;
    }

阻塞队列:
当队列头部为空时,消费数据时阻塞。当数据满了的时候,生产数据时被阻塞。


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


应用:

如何利用队列实现固定线程池连接数?

没有空闲线程时,处理方式:
 非阻塞方式:直接拒绝。
 阻塞方式:1,链表实现支持无限排队的无界队列。
2,数组实现有限大小的有界队列

详解:
线程池没有空闲线程时,新的任务请求线程资源时,线程池该如何处理?各种处理策略又是如何实现的呢?
我们一般有两种处理策略。第一种是非阻塞的处理方式,直接拒绝任务请求;另一种是阻塞的处理方式,将请求排队,等到有空闲线程时,取出排队的请求继续处理。那如何存储排队的请求呢?
我们希望公平地处理每个排队的请求,先进者先服务,所以队列这种数据结构很适合来存储排队请求。我们前面说过,队列有基于链表和基于数组这两种实现方式。这两种实现方式对于排队请求又有什么区别呢?
基于链表的实现方式,可以实现一个支持无限排队的无界队列(unbounded queue),但是可能会导致过多的请求排队等待,请求处理的响应时间过长。所以,针对响应时间比较敏感的系统,基于链表实现的无限排队的线程池是不合适的。
而基于数组实现的有界队列(bounded queue),队列的大小有限,所以线程池中排队的请求超过队列大小时,接下来的请求就会被拒绝,这种方式对响应时间敏感的系统来说,就相对更加合理。不过,设置一个合理的队列大小,也是非常有讲究的。队列太大导致等待的请求太多,队列太小会导致无法充分利用系统资源、发挥最大性能。
除了前面讲到队列应用在线程池请求排队的场景之外,队列可以应用在任何有限资源池中,用于排队请求,比如数据库连接池等。实际上,对于大部分资源有限的场景,当没有空闲资源时,基本上都可以通过“队列”这种数据结构来实现请求排队。


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值