简介
多线程中通过队列很容易共享数据, 比方经典的
生产者
和消费者
模型中, 通过队列能够很不便的实现数据共享。假如咱们有若干生产者线程, 又有若干消费者线程, 生产者线程能够通过队列将数据共享给消费者。然而生产者和消费者在某个时间段内, 万一产生数据处理速度不匹配的状况呢? 如果生产者生产数据的速度远大于消费者生产数据的速度, 现实状况下是当生产者产生的数据达到一个阈值之后, 那么生产者必须暂停一下 (阻塞生产者线程), 以便消费者能够把数据生产掉。在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
, 关注点应该在它的put
和take
办法上, 因为这两个办法是带阻塞。
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
罕用的是
ArrayBlockingQueue
和LinkedBlockingQueue
关注微信公众号:【入门小站】, 解锁更多知识点。