目录
一,阻塞队列
1.1 什么是阻塞队列
1.2 生产者消费者模型
1.3 标准库中的阻塞队列
1.4 阻塞队列的实现
一,阻塞队列
1.1 什么是阻塞队列
阻塞队列(BlockingQueue)是一种特殊的队列,遵循 "先进先出" 的原则,它有两个特点:1. 队列为空时等待获取元素。2. 队列已满时等待插入元素的操作。具体来说,当一个线程试图从空的阻塞队列中获取元素时,该线程将被阻塞,直到队列中有可用元素为止。同样地,当一个线程试图向已满的阻塞队列中插入元素时,该线程将被阻塞,直到队列中有空闲位置为止。
1.2 生产者消费者模型
阻塞队列通常用于实现生产者-消费者模式,其中生产者线程将数据放入队列,而消费者线程从队列中取出数据进行处理。那么这么做有什么好处呢?
- 阻塞队列类似于一个缓冲区,可以平衡生产者和消费者的处理能力,比如:在318,双11这些日子的时候,服务器会在同一时刻收到大量的购物订单,如果一股脑的交给一个服务器可能扛不住,这个时候就可以把这些订单放入到阻塞队列中,然后再由服务器慢慢处理每个订单,再举一个生活中的例子,三峡大坝(阻塞队列),当汛期到来时,三峡大坝会将多余的水储存住,防止下游出现洪涝灾害,等到枯水期的时候,再将储存的水排到下游,起到了 "削峰填谷" 的作用。
- 能够使代码解耦合,简单来说,就是降低代码之间的联系,这样就不会出现 "牵一发而动全身" 的现象。
1.3 标准库中的阻塞队列
标准库中提供了一个BlockingQueue的接口,它继承了Queue类,所以它包含Queue的所有方法,常见的阻塞队列实现包括ArrayBlockingQueue、LinkedBlockingQueue等。我们通常使用这些类中的 put() 和 take() 方法,因为其他的方法不具备 "阻塞" 特性。
import java.util.concurrent.*;
public class Demo {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();
blockingQueue.put("111");
String t = blockingQueue.take();
}
}
1.4 阻塞队列的实现
这里我们使用循环数组的方式来实现阻塞队列。
public class MyBlockingQueue {
private int[] arr = new int[10];//队列
//防止出现内存可见性的问题
private volatile int head;//头
private volatile int tail;//尾
private volatile int size;//已经存了几个元素
public MyBlockingQueue(){
head = 0;
tail = 0;
size = 0;
}
public void put(int val) throws InterruptedException {
synchronized (this){
if(size == arr.length){
this.wait();//队列满了,阻塞
}
arr[tail] = val;
tail = (tail+1)%arr.length;
size++;
this.notify();//唤醒take()中的wait()
}
}
public int take() throws InterruptedException {
synchronized (this) {
if(size == 0){
this.wait();//队列为空,阻塞
}
int tmp = arr[head];
head = (head+1)%arr.length;
size--;
this.notify();//唤醒put()中的wait()
return tmp;
}
}
}