一.概述
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。
二.方法
抛出异常 | 特殊值 | 阻塞 | 超时 | |
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() | 不可用 | 不可用 |
四组不同的行为方式解释:
1(异常)
如果试图的操作无法立即执行,抛一个异常。
2(特定值)
如果试图的操作无法立即执行,返回一个特定的值(常常是 true / false)。
3(阻塞)
如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。
4(超时)
如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。返回一个特定值以告知该操作是否成功(典型的是 true / false)。
三.种类
- ArrayBlockingQueue:由数组结构组成的有界阻塞队列。
- LinkedBlockingQueue:由链表结果组成的有界阻塞队列(默认大小Integer.MAX_VALUE)阻塞队列。(接近无界)
- SychronousQueue:不存储元素的阻塞队列,也即单个元素队列。(最后代码演示)
- PriorityBlockingQueue:支持优先级排序的无界阻塞队列。
- DelayQueue:使用优先级队列实现的延迟无界阻塞队列。
- LinkedTransferQueue:由链表结构组成的无界阻塞队列。
- LinkedBlockingDeque:由链表结构组成的双端阻塞队列。
四.生产者消费者案例
生产者:
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable{
BlockingQueue<String> queue;
public Producer(BlockingQueue<String> queue){
this.queue = queue;
}
@Override
public void run() {
try{
String product_name = "鸡蛋"+Thread.currentThread().getName();
System.out.println("生产者:母鸡下了鸡蛋"+Thread.currentThread().getName());
queue.put(product_name); //如果队满,则阻塞
}catch (Exception e){
e.printStackTrace();
}
}
}
消费者:
import java.util.concurrent.BlockingQueue;
public class Consumer implements Runnable{
BlockingQueue<String> blockingQueue;
public Consumer(BlockingQueue<String> blockingQueue){
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
try {
String product_name = blockingQueue.take(); //如果队空,则阻塞
System.out.println("消费者:工人拿走了"+product_name);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试类:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
public class ProducerConsumerTest {
public static void main(String[] args) {
BlockingQueue<String> queue = new LinkedBlockingDeque<>(2);
for (int i = 1; i < 6; i++) {
new Thread(new Producer(queue), i+"").start();
new Thread(new Consumer(queue), i+"").start();
}
}
}
结果: