最近得空,想写篇文章好好说说 java 线程池问题,我相信许多人都一知半解的,包罗我本身在仔仔细细看源码之前,也有很多的不解,甚至有些处所我一直都没有领略到位。
说到线程池实现,那么就不得不涉及到各类 BlockingQueue 的实现,那么我想就 BlockingQueue 的问题和各人分享分享我相识的一些常识。
本文没有像之前阐明 AQS 那样一行一行源码阐明白,不外照旧把个中最重要和最难领略的代码说了一遍,所以难免篇幅略长。本文涉及到较量多的 Doug Lea 对 BlockingQueue 的设计思想,但愿有心的读者真的可以有一些收获,我以为本身照旧写了一些干货的。
本文直接参考 Doug Lea 写的 java doc 和注释,这也是我们在进修 java 并发包时最好的质料了。但愿各人能有所思、有所悟,进修 Doug Lea 的代码气势气魄,并将其优雅、严谨的作风应用到我们写的每一行代码中。
BlockingQueue
开篇先先容下 BlockingQueue 这个接口的法则,后头再看其实现。
首先,最根基的来说, BlockingQueue 是一个先进先出的行列(Queue),为什么说是阻塞(Blocking)的呢?是因为 BlockingQueue 支持当获取行列元素可是行列为空时,会阻塞期待行列中有元素再返回;也支持添加元素时,假如行列已满,那么比及行列可以放入新元素时再放入。
BlockingQueue 是一个接口,担任自 Queue,所以其实现类也可以作为 Queue 的实现来利用,而 Queue 又担任自 Collection 接口。
BlockingQueue 对插入操纵、移除操纵、获取元素操纵提供了四种差异的要领用于差异的场景中利用:1、抛出异常;2、返回非凡值(null 或 true/false,取决于详细的操纵);3、阻塞期待此操纵,直到这个操纵乐成;4、阻塞期待此操纵,直到乐成可能超时指按时间。总结如下:
Throws exception | Special value | Blocks | Times out | |
---|---|---|---|---|
Insert | add(e) | offer(e) | put(e) | offer(e, time, unit) |
Remove | remove() | poll() | take() | poll(time, unit) |
Examine | element() | peek() | not applicable | not applicable |
BlockingQueue 的各个实现都遵循了这些法则,虽然我们也不消死记这个表格,知道有这么回事,然后写代码的时候按照本身的需要去看要领的注释来选取符合的要领即可。
对付 BlockingQueue,我们的存眷点应该在 put(e) 和 take() 这两个要领,因为这两个要领是带阻塞的。
BlockingQueue 不接管 null 值的插入,相应的要领在遇到 null 的插入时会抛出 NullPointerException 异常。null 值在这里凡是用于作为非凡值返回(表格中的第三列),代表 poll 失败。所以,假如答允插入 null 值的话,那获取的时候,就不能很好地用 null 来判定到底是代表失败,照旧获取的值就是 null 值。
一个 BlockingQueue 大概是有界的,假如在插入的时候,发明行列满了,那么 put 操纵将会阻塞。凡是,在这里我们说的无界行列也不是说真正的无界,而是它的容量是 Integer.MAX_VALUE(21亿多)。
BlockingQueue 是设计用来实现出产者-消费者行列的,虽然,你也可以将它当做普通的 Collection 来用,前面说了,它实现了 java.util.Collection 接口。譬喻,我们可以用 remove(x) 来删除任意一个元素,可是,这类操纵凡是并不高效,所以只管只在少数的场所利用,好比一条动静已经入队,可是需要做打消操纵的时候。
BlockingQueue 的实现都是线程安详的,可是批量的荟萃操纵如 addAll
, containsAll
, retainAll
和 removeAll
不必然是原子操纵。如 addAll(c) 有大概在添加了一些元素后半途抛出异常,此时 BlockingQueue 中已经添加了部门元素,这个是答允的,取决于详细的实现。
BlockingQueue 不支持 close 或 shutdown 等封锁操纵,因为开拓者大概但愿不会有新的元素添加进去,此特性取决于详细的实现,不做强制约束。
最后,BlockingQueue 在出产者-消费者的场景中,是支持多消费者和多出产者的,说的其实就是线程安详问题。
相信上面说的每一句都很清楚了,BlockingQueue 是一个较量简朴的线程安详容器,下面我会阐明其详细的在 JDK 中的实现,这里又到了 Doug Lea 演出时间了。
BlockingQueue 实现之 ArrayBlockingQueue
ArrayBlockingQueue 是 BlockingQueue 接口的有界行列实现类,底层回收数组来实现。
其并发节制回收可重入锁来节制,不管是插入操纵照旧读取操纵,都需要获取到锁才气举办操纵。