我们平时开发中好像很少使用到BlockingQueue(阻塞队列),比如我们想要存储一组数据的时候会使用ArrayList,想要存储键值对数据会使用HashMap,在什么场景下需要用到BlockingQueue呢?
1. BlockingQueue的应用场景当我们处理完一批数据之后,需要把这批数据发给下游方法接着处理,但是下游方法的处理速率不受控制,可能时快时慢 。如果下游方法的处理速率较慢,会拖慢当前方法的处理速率,这时候该怎么办呢?
你可能想到使用线程池,是个办法,不过需要创建很多线程,还要考虑下游方法支不支持并发,如果是CPU密集任务,可能多线程比单线程处理速度更慢,因为需要频繁上下文切换 。
这时候就可以考虑使用BlockingQueue,BlockingQueue最典型的应用场景就是上面这种生产者-消费者模型 。生产者往队列中放数据,消费者从队列中取数据,中间使用BlockingQueue做缓冲队列,也就解决了生产者和消费者速率不同步的问题 。
文章插图
你可能联想到了消息队列(MessageQueue),消息队列相当于分布式阻塞队列,而BlockingQueue相当于本地阻塞队列,只作用于本机器 。对应的是分布式缓存(比如:Redis、Memcache)和本地缓存(比如:Guava、Caffeine) 。
另外很多框架中都有BlockingQueue的影子,比如线程池中就用到BlockingQueue做任务的缓冲 。消息队列中发消息、拉取消息的方法也都借鉴了BlockingQueue,使用起来很相似 。
今天就一块深入剖析一下Queue的底层源码 。
2. BlockingQueue的用法BlockingQueue的用法非常简单,就是放数据和取数据 。
/** * @apiNote BlockingQueue示例 * @author 一灯架构 */public class Demo {public static void main(String[] args) throws InterruptedException {// 1. 创建队列,设置容量是10BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);// 2. 往队列中放数据queue.put(1);// 3. 从队列中取数据Integer result = queue.take();}}
为了满足不同的使用场景,BlockingQueue设计了很多的放数据和取数据的方法 。操作抛出异常返回特定值阻塞阻塞一段时间放数据
add
offer
put
offer(e, time, unit)
取数据remove
poll
take
poll(time, unit)
取数据(不删除)element()
peek()
不支持不支持这几组方法的不同之处就是:- 当队列满了,再往队列中放数据,add方法抛异常,offer方法返回false,put方法会一直阻塞(直到有其他线程从队列中取走数据),offer方法阻塞指定时间然后返回false 。
- 当队列是空,再从队列中取数据,remove方法抛异常,poll方法返回null,take方法会一直阻塞(直到有其他线程往队列中放数据),poll方法阻塞指定时间然后返回null 。
- 当队列是空,再去队列中查看数据(并不删除数据),element方法抛异常,peek方法返回null 。
3. BlockingQueue实现类BlockingQueue常见的有下面5个实现类,主要是应用场景不同 。
- ArrayBlockingQueue
基于数组实现的阻塞队列,创建队列时需指定容量大小,是有界队列 。
- LinkedBlockingQueue
基于链表实现的阻塞队列,默认是无界队列,创建可以指定容量大小
- SynchronousQueue
一种没有缓冲的阻塞队列,生产出的数据需要立刻被消费
- PriorityBlockingQueue
实现了优先级的阻塞队列,基于数据显示,是无界队列
- DelayQueue
实现了延迟功能的阻塞队列,基于PriorityQueue实现的,是无界队列经验总结扩展阅读
- 4 Java注解:一个真实的Elasticsearch案例
- 原生JavaScript
- 3 Java注解:一个真实Elasticsearch案例
- JavaWeb完整案例详细步骤
- redis bitmap数据结构之java对等操作
- 公务员工资那么低怎么养家 为什么还有很多人考
- Java工具类 利用Hutool-实现验证码校验
- JavaFx 使用字体图标记录
- 含具体案例 Java8新特性之Stream流
- Java学习之路:流程控制