前言
cpu的资源是有限的,任务处理的速度和线程的个数不是线性相关。相反,过多的线程反而会导致cpu频繁切换,处理性能下降。
当我们向固定大小的线程池请求一个线程时,线程池中没有空闲的资源了,这个时候线程池如何处理请求。这时候我们引入了队列这个数据结构。
1.当我们想对顶大小的线程池中请求一个线程时候,如果线程池中没有空闲资源了,这个时候线程池如何处理这个请求?拒绝请求还是排队请求?
队列的应用很广泛,比如循环队列、阻塞队列、并发队列。
高性能队列disruptor、linux环形存储
java concurrent利用arrayblockingqueue实现公平锁
循环队列
- 循环队列的难点在于确定队空和队满的判定条件。
循环队列tail指向的位置上式没有存储数据的,因此循环队列会浪费一个数组的存储空间。
队列满的条件为:(tail+1)%n==head
队列空的条件为:tail==head
正是因为队满和队空的条件需要不相同,所以循环队列会浪费一个存储单元。
public class CircularQueue {
// 数组:items,数组大小:n
private String[] items;
private int n = 0;
// head 表示队头下标,tail 表示队尾下标
private int head = 0;
private int tail = 0;
// 申请一个大小为 capacity 的数组
public CircularQueue(int capacity) {
items = new String[capacity];
n = capacity;
}
// 入队
public boolean enqueue(String item) {
// 队列满了
if ((tail + 1) % n == head) return false;
items[tail] = item;
tail = (tail + 1) % n;
return true;
}
// 出队
public String dequeue() {
// 如果 head == tail 表示队列为空
if (head == tail) return null;
String ret = items[head];
head = (head + 1) % n;
return ret;
}
}
阻塞队列和并发队列
- 1.阻塞队列:在队列的基础上增加了阻塞操作,当队列为空的时候,从队头取数据会被阻塞。如果队列已经满了,那么插入数据的操作会被阻塞,直到队伍中有空闲位置再插入数据,然后再返回。
- 2.上面的定义是一个典型的生产者-消费者模型。当生产者的数据生产过快,存储数据的队列很快就满了这是生产者就要阻塞等待,直到消费者消费了数据,生产者才会继续生产。
- 3.并发队列,最简单直接的方式在enqueue和的queue的方法上枷锁。
问题:线程池没有空闲线程时,新的任务请求线程资源时,线程池该如何处理?
- 第一种是非阻塞的处理方式,直接拒绝任务请求;另一种是阻塞的处理方式,等优空闲线程的时候,去除排队的请求继续处理。
问题:基于链表和数组实现等待队列的区别?
*链表:实现了一个无限排队的队列,但是过多等待请求会是请求处理的响应时间过长,基于链表实现的无限排队是不合适的。
*基于数组:队列大小有限,队列太大等待请求太多,队列太小无法充分利用系统资源,发挥最大性能。
队列可以应用在任何有限资源池中,用于排队请求,比如数据库连接池等。对于大部分资源有限的场景,当没有空闲资源时,基本上都可以通过队列实现请求排队。