目录
阻塞队列
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提供了如下的常用方法,但是请注意:并非所有的方法都会产生队列阻塞的效果。
其中:阻塞的方法是: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;//初始化阻塞队列}//线程任务@Overridepublic 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;}//执行线程任务@Overridepublic 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//methodspublic static void main(String[] args) {//创建阻塞队列ArrayBlockingQueue-指定容量为10ArrayBlockingQueue 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();}
}
如上图所示,该案例中,会不断执行发生生产者生产、消费者消费的子线程任务,并打印信息。