共计 1485 个字符,预计需要花费 4 分钟才能阅读完成。
生产者消费者模式最外围的局部是生产者与消费者之间的非凡容器,而阻塞队列是非凡容器最常见的实现。JDK 中定义了阻塞队列接口 BlockingQueue,JDK 通过该接口为咱们提供了很多种阻塞队列的实现,其中包含本节的配角 ArrayBlockingQueue,该类位于 java.util.concurrent.ArrayBlockingQueue.java。该类须要实现的外围办法如下,上面咱们详细分析 ArrayBlockingQueue 的实现原理。
从名字能够看出它的存储构造就是一个数组,即基于数组实现了一个 FIFO 的阻塞队列。新元素都插入到队列尾部,于是最先进入的元素在队列头而最初进入的元素在队列尾部。该数组是有界的,所以结构时须要制订数组的大小。此外,该阻塞队列还提供偏心和非偏心两种模式。
应用例子
在剖析 ArrayBlockingQueue 的实现原理之前咱们先通过几个例子来理解它的应用。例子一中咱们创立了一个 ArrayBlockingQueue 对象,而后通过五个线程去生产数据并 put 到阻塞队列,二主线程则充当生产端,一直将阻塞队列中的数据取出生产。程序输入如下:
次要展现了阻塞队列空间满了产生阻塞,咱们创立一个最大长度为 4 的阻塞队列,而后通过五个线程别离产生一个数据 put 到阻塞队列中,但因为阻塞队列最大长度为 4,所以在 put 四个数据后会产生阻塞。
次要展现了阻塞队列为空时产生阻塞,咱们创立一个最大长度为 10 的阻塞队列,而后没有生产者产生数据,却又一个消费者调用 take 生产数据。因为阻塞队列为空,所以产生了阻塞。
实现原理
咱们先看 ArrayBlockingQueue 类的属性和构造函数。其中 count 变量示意队列的长度大小,takeIndex 和 putIndex 别离示意队列入队和出队的索引,items 是一个 Object 数组用于保留队列的元素,lock 是并发管制锁,notEmpty 和 notFull 别离示意队列非空时和非满时的条件。提供两个构造函数,咱们在创立时指定队列的大小,另外一个是偏心模式参数,默认是非偏心的。锁对象应用的是 ReentrantLock 对象,偏心机制也应用的是它的,它的偏心机制咱们在后面的章节中曾经深入分析过了。notEmpty 和 notFull 条件对象通过锁对象的 newCondition 创立。
put 和 take 办法是阻塞队列的入队和出队办法,它们会间接调用 enqueue 和 dequeue 办法。其中 put 办法会查看入队的元素不能为 null,须要先获取锁后才执行 enqueue 办法保护数组,如果数组长度曾经达到最大长度则调用 notFull 条件的 await 办法期待。take 办法会先获取锁后才执行 dequeue 办法保护数组,如果数组长度为 0 则调用 notEmpty 条件的 await 办法期待。
offer 和 poll 办法则是反对超时的阻塞队列的入队和出队办法,能够看到次要的区别就在于它们别离调用了 notFull 和 notEmpty 条件的 awaitNanos 办法进行期待。入队时如果超过指定的超时工夫则会返回 false,示意入队超时导致失败。而出队时如果超过指定的超时工夫则会返回 null,示意出队超时导致失败。
总结
围绕着 JDK 中 BlockingQueue 的其中一种实现,即 ArrayBlockingQueue。它的根本构造是应用数组来保留阻塞队列的元素,数组的长度有限度,并且提供了偏心和非偏心模式。对它的实现原理进行剖析,为了不便咱们仅保留了 ArrayBlockingQueue 最外围的源码,只有咱们能了解透彻这些内容就曾经能把握它的实现原理了。举荐浏览