Java多线程之阻塞队列
Java核心技术卷(10th)读书笔记
-
对于许多线程问题, 可以通过使用一个或多个队列以优雅且安全的方式将其形式化。生 产者线程向队列插人元素, 消费者线程则取出它们。使用队列,可以安全地从一个线程向另 一个线程传递数据。
-
当试图向队列添加元素而队列已满, 或是想从队列移出元素而队列为空的时候, 阻塞队 列(blocking queue ) 导致线程阻塞。 在协调多个线程之间的合作时,阻塞队列是一个有用的 工具。工作者线程可以周期性地将中间结果存储在阻塞队列中。其他的工作者线程移出中间 结果并进一步加以修改。队列会自动地平衡负载。如果第一个线程集运行得比第二个慢, 第 二个线程集在等待结果时会阻塞。如果第一个线程集运行得快, 它将等待第二个队列集赶上 来。
阻塞队列的方法
方法 正常动作 特殊情况下的动作 add 添加一个元素 如果队列满,则抛出 IllegalStateException
异常element 返回队列的头元素 如果队列空,抛出 NoSuchElementException
异常offer 添加一个元素并返回 true 如果队列满,返回 false
peek 返回队列的头元素 如果队列空, 则返回 null
poll 移出并返回队列的头元素 如果队列空, 则返回 null
put 添加一个元素 如果队列满, 则阻塞 remove 移出并返回头元素 如果队列空, 则抛出 NoSuchElementException
异常take 移出并返回头元素 如果队列空, 则阻塞 如果将队列当作线程管理工具来使用, 将要用到
put
和take
方法。当试图向满的队列中添加或从空的队列 中移出元素时,add
、remove
和element
操作抛出异常。当然,在一个多线程程序中, 队列会在任何时候空或满, 因此,一定要使用offer
、poll
和peek
方法作为替代。这些方法如果不能完成任务,只是给出一个错误提示而不会抛出异常。poll
和peek
方法返回空来指示失败。 因此,向这些队列中插入null
值是非法的。还有带有超时的 offer 方法和 poll 方法的变体。
-
java.util.concurrent
包提供了阻塞队列的几个变种。-
默认情况下,
LinkedBlockingQueue
的容量是没有上边界的,但是,也可以选择指定最大容量。 -
LinkedBlockingDeque
是一个双端的版本。 -
ArrayBlockingQueue
在构造时需要指定容量,并且有一个可选的参数来指定是否需要公平性。若设置了公平参数, 则那么等待了最长时间的线程会优先得到处理。通常,公平性会降低性能,只有在确实非常需要时才使用它。 -
PriorityBlockingQueue
是一个带优先级的队列, 而不是先进先出队列。元素按照它们的优先级顺序被移出。该队列是没有容量上限,但是,如果队列是空的, 取元素的操作会阻塞。 -
最后,
DelayQueue
包含实现Delayed
接口的对象:interface Delayed extends Comparable { long getDelay(TimeUnit unit); }
getDelay
方法返回对象的残留延迟。负值表示延迟已经结束。元素只有在延迟用完的情 况下才能从DelayQueue
移除。还必须实现compareTo
方法。DelayQueue
使用该方法对元素进行排序。 -
JavaSE 7
增加了一个TransferQueue
接口,允许生产者线程等待, 直到消费者准备就绪 可以接收一个元素。如果生产者调用q.transfer(iteni)
; 这个调用会阻塞, 直到另一个线程将元素( item) 删除。LinkedTransferQueue
类实现了这个接口。
-