阻塞队列就是能够
在队列为空时,从队列里取出元素的操作将被阻塞。
当队列为满时,向队列中添加元素的操作会被阻塞。
Java中也向我们提供了对应的集合类,BlockingQueue阻塞队列属于一个接口,它的底层有七个实现类:
- ArrayBlockQueue:由数组结构组成的有界阻塞队列
- LinkedBlockingQueue:由链表结构组成的有界(但是默认大小 Integer.MAX_VALUE)的阻塞队列
- 有界,但是界限非常大,相当于无界,可以当成无界
- PriorityBlockQueue:支持优先级排序的无界阻塞队列
- DelayQueue:使用优先级队列实现的延迟无界阻塞队列
- SynchronousQueue:不存储元素的阻塞队列,也即单个元素的队列
- 生产一个,消费一个,不存储元素,不消费不生产
- LinkedTransferQueue:由链表结构组成的无界阻塞队列
- LinkedBlockingDeque:由链表结构组成的双向阻塞队列
我们通过代码实现一个ArrayBlockQueue
实现:
阻塞队列的特点,阻塞队列首先我们就要使用数组实现一个环形队列
环形队列实现的核心就在于,如何解决head==tail时到底是满了还是空的问题。
一般有三种解决方式:
1、设置一个标志位,如果第一次遇到的时候设置为false,第二次遇到就能够区分。
2、多设一个空位,浪费一个数组空间,这时判满就可以使判断满和判断空的条件区分开。
3、多设置一个成员变量size,size==elem.length时就是满 ,size==0时为空。
这里我们使用最简单的方式,也就是第三种。
class MyBlockQueue{
private int[] elem=new int[1000];
private int head=0;
private int tail=0;
private int size=0;
public void put(int data){
if(this.size==this.elem.length){
return ;
}
this.elem[tail++]=data;
this.size++;
if(this.tail>=this.elem.length){
this.tail=0;
}
}
public int take(){
if(this.size==0){
return 0;
}
int ret=this.elem[head++];
this.size--;
if(this.head>=this.elem.length){
this.head=0;
}
return ret;
}
}
然后要实现的就是阻塞功能:
阻塞功能就是
在队列为空时,从队列里取出元素的操作将被阻塞。
当队列为满时,向队列中添加元素的操作会被阻塞。
所以我们当队列满的时候就让该线程调用wait方法阻塞,当取出完元素的时候就把该线程调用notify唤醒。
同样的当队列空时调用wait阻塞,当添加完元素的时候就把该线程调用notify唤醒。
class MyBlockQueue{
private int[] elem=new int[1000];
private int head=0;
private int tail=0;
private int size=0;
public void put(int data) throws InterruptedException {
if(this.size==this.elem.length){
this.wait();
}
this.elem[tail++]=data;
this.size++;
if(this.tail>=this.elem.length){
this.tail=0;
}
this.notify();
}
public int take() throws InterruptedException {
if(this.size==0){
this.wait();
}
int ret=this.elem[head++];
this.size--;
if(this.head>=this.elem.length){
this.head=0;
}
this.notify();
return ret;
}
}
实现线程安全
如果有多个线程同时调用take方法时,可能还会出现bug。我们把take操作加上锁,这样就实现线程安全了。这就是线程安全的阻塞队列。
class MyBlockQueue{
private int[] elem=new int[1000];
private int head=0;
private int tail=0;
private int size=0;
public void put(int data) throws InterruptedException {
synchronized (this){
if(this.size==this.elem.length){
this.wait();
}
this.elem[tail++]=data;
this.size++;
if(this.tail>=this.elem.length){
this.tail=0;
}
this.notify();
}
}
public int take() throws InterruptedException {
synchronized (this){
if(this.size==0){
this.wait();
}
int ret=this.elem[head++];
this.size--;
if(this.head>=this.elem.length){
this.head=0;
}
this.notify();
return ret;
}
}
}