写点什么

并发编程系列:阻塞队列的实现原理

发布于: 2021 年 02 月 12 日
并发编程系列:阻塞队列的实现原理

一 定义

阻塞队列(Blocking Queue)是一个支持两个附加操作:阻塞的插入,和阻塞的移除的队列。阻塞插入:当队列满时,队列会阻塞插入元素的线程,直到队列不满;阻塞移除:队列为空时,获取元素的线程会等待队列为非空。

从定义中,可以看到很接近我们所了解的生产者-消费者模式,事实上,也确实如此。阻塞队列就是生产者用来存放元素,消费者用来获取元素的容器。

二 操作

插入和移除操作的处理方式如下图所示:

关于异常,阻塞队列的异常发生在队列满和对列空的情况。队列满继续插入时,会抛 IllegalStateException 异常;队列空时,从队列取元素时会抛 NoSuchElementException 异常。

当阻塞队列满时,如果生产者线程往队列里 put 元素,队列会一直阻塞生产者线程,知道队列可用或者响应中断退出;

队列空时,如果消费者线程从队列里取(take)元素,队列会阻塞住消费者线程,直到队列非空。

超时退出:当阻塞队列满时,如果生产者线程往队列里插入元素,队列会阻塞生产者线程一段时间,如果超过指定时间,生产者线程就会退出。

注:如果是无界阻塞队列,那么就不会出现满队列的情况,使用 put 或 offer 方法永远不会阻塞。但可能会导致资源耗费过多,所以需要慎用!

三 JDK 的阻塞队列

ArrayBlockingQueue:数组实现的有界阻塞队列。先进先出原则对队列内元素排序

LinkedBlockingQueue:用链表实现的有界阻塞队列。队列的默认和最大长度为 Integer.MAX_VALUE。队列也是按照先入先出原则对元素进行排序。

PriorityBlockingQueue:支持优先级的无界阻塞队列。默认情况下元素使用自然顺序生序排序,但也支持自定义 compareTo()方法指定排序规则,或在构造方法中传入 Comparator。

DelayQueue:支持延时获取元素的无界阻塞队列,队列使用的 PriorityQueue 实现,并且必须实现 Delayed 接口,指定延迟时间。

SynchronousQueue:不存储元素的阻塞队列,每个 put 必须等待一个 take,否则不能继续添加元素。

LinkedTransferQueue:链表结构组成的 TransferQueue,支持 transfer 给消费者操作。

LinkedBlockingDeque:链表结构组成的双向阻塞队列,即队列的两端都支持插入和移除元素。

四 实现原理

从前面的内容可知,阻塞队列实现的最大难点是阻塞,包括阻塞的时机,以及具体的实现方式,同时需要保证生产者和消费者的信息感知。

JDK 中的实现,是使用通知模式,也就是当生产者往满队列中添加元素时,会阻塞生产者,消费者消费一个元素后,通知生产者当前队列可用。以 ArrayBlockingQueue 为例,JDK 中源码实现如下:

通知生产者:


队列不可用阻塞生产者,使用 LockSupport.park(this):


发布于: 2021 年 02 月 12 日阅读数: 24
用户头像

磨炼中成长,痛苦中前行 2017.10.22 加入

微信公众号【程序员架构进阶】。多年项目实践,架构设计经验。曲折中向前,分享经验和教训

评论

发布
暂无评论
并发编程系列:阻塞队列的实现原理