队列的简单理解
定义:我们可以把它想象成排队买票先来的先买,后来的人只能站在队伍的末尾,不允许插队。
队的特点:先进先出。两个基本操作:入队和出队。
入队指的是将数据放到队伍尾部,出队指的是从队列头部取出数据
基于数组实现的队列
public class ArrayQueue{
private String[] items;
private int n=0;
private int head=0; //队头下标
private int tail=0; //队尾下标
public ArrayQueue(int capacity){
items=new String[capacity];
n=capacity;
}
public boolean enqueue(string item){
if (tail==n)
return false; //tail=n表示队列已满
items[tail]=item;
++tail;
return true;
}
public boolean dequeue{
if (head=tail)
return null; //head=tail表示队列为空
String ret=items[head];
++head;
return ret;
}
}
对于队列我们需要两河指针 一个head指针,指向队头;一个tail指针,指向队尾。
假设下,
当a,b,c,d依次入队后,队列中的head指针指向下标为0的位置,tail指针指向下标为4的位置,
当ab出队后,队列中head指针指向下标为2的位置,tail指针指向下标为4的位置
随着不断入队和出队 head和tail指针都会持续往后移动
当tail指针移到最右边的时候,即便数组中还有未占用的空间我们也无法添加数据
实际上我们并不需要每次出队是都进行搬移数据。
只有当tail指针的数据移动到数组的最右边后,如果有新的数据要入队,我们才集中触发依次数据搬移的操作
将head指针和tail指针的数据整体搬移到数组从0开始的位置。
对此我们对enqueue方法
1 public boolean enqueue(String item){
2 if (tail==n){
3 if (head==0)
4 return fasle; //tail==n&&head=0 表示队列已满
5 for (int i=head;i<tail;++i){ //数据搬移
6 items[i-head]=items[i];
7 }
8 tail=tail-head;
9 head=0;
10 }
11 items[tail]=item; //插入数据
12 ++tail;
13 return true;
14 }
循环队列
当我们把队列的首尾相连那么它就变成了循环队列,这样就避免了tail==n时的数据搬移操作了。
对于循环队列 判断空为 head=tail 判断满是存在一个关系 (tail+1)%n=head;
public class CircularQueue{
private String[] items;
private int n=0;
private int head=0;
private int tail=0;
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(){
if (head==tail)
return null;
String ret=items[head];
head=(head+1)%n;
return ret;
}
}
阻塞队列
就是队列加上阻塞特性,当队列为空的时候从队头取数据会被阻塞,直到队列有数据才返回,
在队列已满时,插入数据会被阻塞,直到队列有空闲位置。
并发队列
线程安全的队列又称为并发队列,可以基于数据的循环列表利用CAS原子操作实现并发队列。
引申
当向固定大小的线程池请求一个线程的时候,线程池如果没有空闲资源,这个时候线程池该如何处理这个请求?
是拒绝还是要求排队?
对于上面情况一般有两个策略
1.非阻塞处理,当线程池没有空闲资源时,直接拒绝新的线程请求。
2.非阻塞处理,请求排队,有资源的时候取出排队的请求继续处理
我们可以进行队列存储排队请求,如果我们选择基于链表的实现方式,可以实现一个支持无限排队的无界队列
但是会导致过多的请求排队等待,请求处理时间过长
选择基于数组的实现有界队列,当排队满的时候会拒绝排队。不过,需要设置一个大小合理的队列,太大导致请求时间过长
太小导致无法充分利用系统资源