目录
阻塞队列
BlockingQueue的常用方法
生产者消费者应用场景
阻塞队列
阻塞队列BlockingQueue继承自父类Queue,该队列是线程安全的,可以安全的与多个生产者和消费者线程一起使用。
与阻塞队列相对的,存在“非阻塞队列”的概念,那么两者在入队和出队时的区别是什么呢?答案如下图所示,
此外,在jdk1.8的源码中,对BlockingQueue的文档注释信息与简单翻译如下,
A {@link java.util.Queue} that additionally supports operations that wait for the queue to become non-empty when retrieving an element, and wait for space to become available in the queue when storing an element.
阻塞队列,当获取元素时,会等待队列变为非空状态,才会返回元素值;当写入元素时,会等待队列变为非满状态时,再将其写入。
核心思想如下:
①阻塞队列在变为空时,继续执行取出队列元素的操作时,会发生阻塞,直到队列中有新的元素被写入时,才停止阻塞,取出元素;
②阻塞队列在已满时,继续执行写入元素的操作时,会发生阻塞,直到队列中已有的元素被消费而产生空位时,才停止阻塞,写入元素。
BlockingQueue的常用方法
BlockingQueue提供了如下的常用方法,但是请注意:并非所有的方法都会产生队列阻塞的效果。
其中:阻塞的方法是:put()-添加、take()-取出。
生产者消费者应用场景
阻塞队列的一个经典应用场景就是:生产者、消费者问题。
如下示例代码中,基于BlockingQueue阻塞队列与子类ArrayBlockingQueue有限阻塞队列,分别创建了2个生产者线程、1个消费者线程。2个生产者线程每隔2秒生产一个随机数,供这1个消费者进行消费。
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
//生产者
class Producer implements Runnable{
private final BlockingQueue blockingQueue;//阻塞队列
private final Random random = new Random();//随机数生成器
//构造器
public Producer(BlockingQueue queue){
this.blockingQueue = queue;//初始化阻塞队列
}
//线程任务
@Override
public void run() {
while (true){
//添加产品到阻塞队列
try {
Thread.sleep(2000);//每隔2秒执行一次生产任务
System.out.println("生产者产出产品");
this.blockingQueue.put(this.produce());
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("生产时发生异常");
}
}
}
//生产方法-生产随机数
Object produce(){
return random.nextInt();
}
}
//消费者
class Consumer implements Runnable{
//阻塞队列
private final BlockingQueue blockingQueue;
//构造器
public Consumer(BlockingQueue queue){
this.blockingQueue = queue;
}
//执行线程任务
@Override
public void run() {
while (true){
try {
this.consume(this.blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("消费时发生异常");
}
}
}
//消费方法
public void consume(Object production){
System.out.println("正在消费产品:"+production);
}
}
public class BlockingQueue_Apply {
//properties
//methods
public static void main(String[] args) {
//创建阻塞队列ArrayBlockingQueue-指定容量为10
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(10);
//创建生产者-2个生产商
Producer producer = new Producer(blockingQueue);
Producer producer1 = new Producer(blockingQueue);
//创建消费者
Consumer consumer = new Consumer(blockingQueue);
//生产者线程
Thread producerThread = new Thread(producer);
Thread producerThread1 = new Thread(producer1);
//消费者线程
Thread consumerThread = new Thread(consumer);
//启动线程任务
producerThread.start();
producerThread1.start();
consumerThread.start();
}
}
如上图所示,该案例中,会不断执行发生生产者生产、消费者消费的子线程任务,并打印信息。