乐趣区

关于java:Java高并发之BlockingQueue

简介

多线程中通过队列很容易共享数据, 比方经典的 生产者 消费者 模型中, 通过队列能够很不便的实现数据共享。假如咱们有若干生产者线程, 又有若干消费者线程, 生产者线程能够通过队列将数据共享给消费者。然而生产者和消费者在某个时间段内, 万一产生数据处理速度不匹配的状况呢? 如果生产者生产数据的速度远大于消费者生产数据的速度, 现实状况下是当生产者产生的数据达到一个阈值之后, 那么生产者必须暂停一下 (阻塞生产者线程), 以便消费者能够把数据生产掉。在concurrent 包呈现之前, 开发人员必须手动管制这些细节, 导致开发高性能程序难度较大 (兼顾效率和平安)。concurrent 进去之后, 带来了BlockingQueue(在多线程中, 在某些状况下挂起线程(即阻塞), 一旦条件满足, 被挂起的线程又会被主动唤醒)

BlockingQueue即为阻塞队列, 是一个先进先出的队列, 在某些状况下, 对阻塞队列的拜访可能会造成阻塞, 被阻塞的状况次要有两种。

  • 当对列满时, 进行入队操作时。当一个线程试图对一个曾经满了的队列进行入队操作时, 也将会被阻塞, 除非有一个线程进行了出队列操作。
  • 当队列空时, 进行出队操作时。当一个线程试图对一个为空的队列进行出队列操作时, 也将会被阻塞, 费油有一个线程进行了出队列操作。

阻塞队列是线程平安的, 次要用在生产者消费者的场景上。负责生产的线程一直的制作新对象并插入到阻塞队列中, 直到达到队列的上限值, 从而被阻塞, 直到生产线程对队列进行生产。同理, 负责生产的线程一直的从队列中取出对象进行生产, 直到这个队列为空, 这时生产队列会被阻塞, 除非队列中有新的对象被退出进来。

public interface BlockingQueue<E> extends Queue<E> {}
public interface Queue<E> extends Collection<E> {}

BlockingQueue是一个接口, 继承自 Queue, 所以实现类也能够作为Queue 的实现来应用, 而 Queue 又继承自 Collection 接口。

BlockingQueue对插入操作, 移除操作, 获取元素操作提供了四种不同的办法用于不同的场景, 应用不同的办法, 会有不同的成果。BlockingQueue的各个实现都遵循这些规定。

Throws Exception Special Value Blocks Times Out
insert add(o) offer(o) put(o) offer(o,timeout,timeunit)
remove remove(o) poll() take() poll(timeout,timeunit)
examine element() peek() not applicable not applicable
  • Throws Exception:抛出异样。如果不能马上进行,则抛出异样。
  • Special Value:如果不能马上进行,则返回非凡值,个别是 True 或 False
  • Blocks:如果不能马上进行,则操作会被阻塞,直到这个操作胜利
  • Times Out:如果不能马上进行,操作会被阻塞指定的工夫。如果指定工夫还未执行,则返回非凡值,个别是 True 或 False。

对于 BlockingQueue, 关注点应该在它的puttake办法上, 因为这两个办法是带阻塞。

BlockingQueue不承受 null 值的插入, 相应的办法在碰到 null 的插入时会抛出 NullPointerException 异样,null值通常用于非凡值返回 (表格中的第三列), 代表poll 失败。所以如果容许插入 null 值的话, 那获取的时候, 就不能很好的用 null 来判断到底是失败还是获取的值为null

BlockingQueue实现了 java.util.Collection 接口, 咱们能够应用 remove(x) 来删除任意一个元素, 然而这类操作并不高效, 所以尽量在多数场合应用, 比方一条音讯曾经入队, 然而须要勾销操作的时候。

BlockingQueue的实现都是线程平安的, 然而批量的汇合操作 addAll,containsAll,retainAll,removeAll 不肯定是原子操作, 如 addAll(c) 增加了一些元素后抛出异样, 此时 BlockingQueue 中曾经增加了局部元素, 这个是容许的, 取决于具体实现。

BlockingQueue在生产者 - 消费者的场景中, 是反对多消费者和多消费者的, 说的其实就是线程平安问题。BlockingQueue是一个比较简单的线程平安容器。作为 BlockingQueue 的使用者, 咱们再不必思考何时阻塞线程, 什么时候唤醒线程, 因为这一些 BlockingQueue 都实现了。

无界队列, 并不是大小不限度, 只是它的大小是Integer.MAX_VALUE, 即 int 类型能示意的最大值(2 的 31 次方)-1

BlockingQueue具体实现类

  • ArrayBlockingQueue
  • LinkedBlockingQueue
  • DelayQueue
  • PriorityBlockingQueue
  • SynchronousQueue

罕用的是 ArrayBlockingQueueLinkedBlockingQueue

关注微信公众号:【入门小站】, 解锁更多知识点。

退出移动版