阻塞队列,一个生产消费模式,当:
而亮点就在于什么时候阻塞线程,什么时候唤起线程,则由BlockingQueue一手包办。


ArrayBlockingQueue:底层是一个定长数组,有界阻塞队列
LinkedBlockingQueue:底层是一个链表,有界阻塞队列,但它的默认值其实足够大了(大小默认值为Integer.MAX_VALUE)
DelayQueue:队列中的元素只有到了指定的延迟时间,才能获取到该元素。是无界队列,因此生产者线程永不阻塞
PriorityBlockingQueue:支持优先级排序的无界阻塞队列(优先级的判断通过其构造方法传入Compator对象决定)
SynchronousQueue:无中介,一种不存储元素的阻塞队列、单个元素的队列,一个线程写入了数据,就必须得有一个线程取,否则不能再继续添加,用于传递性的场景
LinkedTransferQueue:底层是一个链表,无界阻塞队列。亮点是其有预占模式,其消费者线程取元素时,若队列为空,就生成一个元素为null的节点入队,消费者线程就等待在这个节点上,后续生产者线程来了发现有个元素为null的节点,就不再入队,直接把数据填充给这个null节点,并唤醒改null节点上等待的消费者线程取走元素
LinkedBlockingDeque:底层是一个链表,双向阻塞队列,可以从队列的两端插入和移除元素
按照队列空或者队列满时的表现,可分为以下四组:

以列为单位来看以上表格的含义:
//创建阻塞队列
BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(3);
//写
for (int i = 0; i < 4; i++) {
blockingQueue.add(i);
}
抛异常:

创建一个阻塞队列,开两个线程分别对这个队列进行写个读,采用上面阻塞列的那一组方法,演示下生产消费者模式:
public class BlockQueueDemo {
public static void main(String[] args) throws InterruptedException {
//创建阻塞队列
BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(3);
//生产者线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
blockingQueue.put(i);
System.out.println(Thread.currentThread().getName() + "线程写数据成功:" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//消费者线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
//每次取之前歇3秒,模拟生产快,消费慢的场景
TimeUnit.SECONDS.sleep(3);
Integer takeValue = blockingQueue.take();
System.out.println(Thread.currentThread().getName() + "线程取数据成功:" + takeValue);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
可以看到,刚开始写线程可以写3个数据到阻塞队列,然后挂起,等消费线程取走一个,则可再写一个,此时,消费慢,阻塞队列满了,生产线程再次自动挂起,进入阻塞。

关于阻塞队列的具体应用 ==> 线程池,下篇整理。