一、阻塞队列
阻塞队列是一种特殊的队列,具有先进先出的特性,且是线程安全的。
主要特性如下:
- 当队列满的时候,继续入队列就会阻塞,直到有其他线程从队列中取走元素。
- 当队列空的时候,继续出队列也会阻塞,直到有其他线程往队列中插入元素。
阻塞队列的一个重要应用场景是实现生产者消费者模型。
1.1 生产者消费者模型
生产者消费者模型是多线程编程中的一种典型编码技巧,用于降低生产者与消费者之间的耦合度。生产者和消费者之间的交易场所就是一个阻塞队列。
该模型的优势包括:
- 解耦合,降低代码耦合度:使用阻塞队列作为交易平台,修改服务器数据时,由于阻塞队列中的结构固定,两个服务器之间的耦合度降低。
- 削峰削谷:在服务器中,波峰是请求量高的时候,波谷是请求量低的时候。如果上游服务器经历波峰,将大量请求传给下游服务器,可能导致下游服务器挂掉。引入阻塞队列后,下游服务器可以依据自己的节奏从队列中拿请求。
但模型也会付出代价:
- 引入阻塞队列之后整体结构会更加复杂,需要部署消息队列服务器。
- 效率可能会有影响。
1.2 Java 提供的阻塞队列
Java 提供了 BlockingQueue 接口(需要导入 java.util.concurrent.BlockingQueue 包)。
主要使用下面 3 个实现了 BlockingQueue 接口的类来实例化阻塞队列:
- 小根堆实现的
PriorityBlockingQueue(需要导入java.util.concurrent.PriorityBlockingQueue包)。 - 数组实现的
ArrayBlockingQueue(需要导入java.util.concurrent.ArrayBlockingQueue包)。 - 链表实现的
LinkedBlockingQueue(需要导入java.util.concurrent.LinkedBlockingQueue包)。
注:LinkedBlockingDeque 等双端队列类也实现了 BlockingQueue 接口。
在阻塞队列中虽然可以使用队列中常用的出队列入队列方法,但是那些方法不带阻塞效果。带阻塞效果的入队列方法是 put,出队列方法是 take,这两个方法都会抛出 InterruptedException 异常。
1.3 实现一个简单生产者消费者模型
实现一个简单的生产者消费者模型:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
public class Demo {
public static void main(String[] args) {
BlockingQueue<Integer> blockingQueue = new LinkedBlockingDeque<>();
(() -> {
;
() {
{
blockingQueue.put(i++);
System.out.println(i + );
} (InterruptedException e) {
e.printStackTrace();
}
}
});
(() -> {
() {
{
blockingQueue.take();
System.out.println(x + );
} (InterruptedException e) {
e.printStackTrace();
}
}
});
producer.start();
consumer.start();
}
}


