写点什么

并发阻塞队列(BlockingQueue)— 生产者消费者模式核心部件

用户头像
码农架构
关注
发布于: 2021 年 01 月 14 日
并发阻塞队列(BlockingQueue)— 生产者消费者模式核心部件

在分析阻塞队列之前我们先看生产者消费者模式,这是一个很常见的模式,生产者负责数据的生产,而消费者则负数据的消费。一般来说生产者与消费者的数量比例是 m:n,该模式最大的好处就是将数据生产方与消费方进行了解耦,使得它们之间不会互相影响。为了将生产者和消费者连接起来,我们需要一个特殊的容器,该容器能存储生产者生产的数据,而消费者则能从该容器中取出数据。



我们可以通过厨师、桌子、顾客来说明生产者消费者模式,厨师就好比生产者,他们制作生产出来美食将放到桌子这个容器中,顾客则好比是消费者,他们从桌子上取出美食进行消费享用。

阻塞队列

生产者消费者模式的核心部分就是生产者和消费者之间的那个特殊容器,我们通过实现一个线程安全且具有一定策略的容器便连接起两端的生产者和消费者。这个容器可以具有队列性质,也可以具有栈性质,亦或是其它数据结构。最常见的就是阻塞队列,队列保证了先进的数据先出,而阻塞则是队列已满时和队列为空时的处理策略,即队列已满时的入队操作和队列为空时的出队操作都会引起阻塞。


下图是阻塞队列工作示意图,线程一、线程二、线程三生产的数据通过 put 操作进行入队,线程四、线程五通过 take 操作进行出队,当队列满时 put 操作会阻塞等待消费者将队列的元素拿走,当队列为空时 take 操作会阻塞等待生产者将数据入队。



模拟实现

根据前面对阻塞队列的介绍,我们试着来模拟实现一个简单的阻塞队列。先看数据结构的设计,可以使用一个数组来存放队列的元素,并通过 head 和 tail 指针来约束先进先出规则。入队操作使用 tail 指向的位置,而出队则使用 head 指向的位置,一旦到达数组尾部就重新从头开始。



下面看看具体的实现,Object 数组用于保存元素,size 表示队列的大小,此外还有 head 和 tail 指针。通过构造函数来指定阻塞队列大小,生产者生产的数据调 put 方法进行入队,如果 size 等于队列最大长度时则调用 wait 阻塞(此时队列已经满了),否则将元素保存到队列中,同时维护 size 和 tail,最后如果 size 等于 1 时要调用 notifyAll 方法通知消费者可以消费了。消费者通过调用 take 方法进行数据消费,如果 size 等于 0 时则调用 wait 阻塞(队列为空需要等待),否则通过 head 获取队列头的元素,同时维护 size 和 head,最后如果 size 等于 queue.length-1 时调用 notifyAll 方法通知生产者可以生产了。


阻塞队列模拟实现

可以通过下面这个例子看模拟阻塞队列例子,输出结果如下,一个线程进行数据生产,一个线程进行数据消费。



BlockingQueue 接口

接下去我们看 JDK  的阻塞队列接口 BlockingQueue,该接口早在 Java 5 时就已经引入了。JDK 为我们提供了很多种阻塞队列的实现,比如 ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue 以及 SynchronousQueue 等等,它们都实现了 BlockingQueue 接口。该接口主要的核心方法如下,这些方法都支持中断,其中 put 方法和 take 方法我们都很熟悉的了,另外 offer 和 poll 两个方法其实对应的是 put 和 take 两个方法,只是它们提供了阻塞超时机制。


总结 

本节讲解了生产者消费者模式,该模式的核心部件是一种特殊的容器,而阻塞队列则是异常很常见的容器。然后我们通过一个数组和 head、tail 指针来模拟实现一个阻塞队列,其中 put 和 take 操作使用了 synchronized 控制多线程的访问,阻塞机制也由它提供。最后我们简单介绍了 JDK 的 BlockingQueue 接口,后面再分几个章节来详细分析 ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue 以及 SynchronousQueue 等阻塞队列的实现。



发布于: 2021 年 01 月 14 日阅读数: 40
用户头像

码农架构

关注

公众号:码农架构 2018.03.22 加入

专注于系统架构、高可用、高性能、高并发类技术分享

评论 (1 条评论)

发布
用户头像
这篇文章对你有帮助吗?作为一名程序工程师,在评论区留下你的困惑或你的见解,大家一起来交流吧!
2021 年 01 月 20 日 10:01
回复
没有更多了
并发阻塞队列(BlockingQueue)— 生产者消费者模式核心部件