引言
最近一个月一直在更新《解读Java源码专栏》,其中跟大家一起剖析了Java的常见的5种BlockingQueue(阻塞队列),今天就盘点一下这几种阻塞队列的优缺点、区别,以及应用场景。
常见的BlockingQueue有以下5种,下面会详细介绍。
- ArrayBlockingQueue
基于数组实现的阻塞队列,创建队列时需指定容量大小,是有界队列。
- LinkedBlockingQueue
基于链表实现的阻塞队列,默认是无界队列,创建可以指定容量大小
- SynchronousQueue
一种没有缓冲的阻塞队列,生产出的数据需要立刻被消费
- PriorityBlockingQueue
实现了优先级的阻塞队列,可以按照元素大小排序,是无界队列
- DelayQueue
实现了延迟功能的阻塞队列,基于PriorityQueue实现的,是无界队列
BlockingQueue简介
这几种阻塞队列都是实现了BlockingQueue接口,在日常开发中,我们好像很少用到BlockingQueue(阻塞队列),BlockingQueue到底有什么作用?应用场景是什么样的?
如果使用过线程池或者阅读过线程池源码,就会知道线程池的核心功能都是基于BlockingQueue实现的。
大家用过消息队列(MessageQueue),就知道消息队列作用是解耦、异步、削峰。同样BlockingQueue的作用也是这三种,区别是BlockingQueue只作用于本机器,而消息队列相当于分布式BlockingQueue。
BlockingQueue作为阻塞队列,主要应用于生产者-消费者模式的场景,在并发多线程中尤其常用。
BlockingQueue是个接口,定义了几组放数据和取数据的方法,来满足不同的场景。
操作 |
抛出异常 |
返回特定值 |
阻塞 |
阻塞一段时间 |
放数据 |
add() |
offer() |
put() |
offer(e, time, unit) |
取数据(同时删除数据) |
remove() |
poll() |
take() |
poll(time, unit) |
取数据(不删除) |
element() |
peek() |
不支持 |
不支持 |
这四组方法的区别是:
ArrayBlockingQueue
LinkedBlockingQueue
与ArrayBlockingQueue区别是:
SynchronousQueue
无论是ArrayBlockingQueue还是LinkedBlockingQueue都是起到缓冲队列的作用,当消费者的消费速度跟不上时,任务就在队列中堆积,需要等待消费者慢慢消费。
如果我们想要自己的任务快速执行,不要积压在队列中,该怎么办?这时候就可以使用SynchronousQueue了。
SynchronousQueue被称为同步队列,当生产者往队列中放元素的时候,必须等待消费者把这个元素取走,否则一直阻塞。消费者取元素的时候,同理也必须等待生产者放队列中放元素。
PriorityBlockingQueue
由于PriorityQueue跟前几个阻塞队列不一样,并没有实现BlockingQueue接口,只是实现了Queue接口,所以PriorityQueue并不算阻塞队列。Queue接口中定义了几组放数据和取数据的方法,来满足不同的场景。
DelayQueue
DelayQueue是一种本地延迟队列,比如希望我们的任务在5秒后执行,就可以使用DelayQueue实现。常见的使用场景有:
- 订单10分钟内未支付,就取消。
- 缓存过期后,就删除。
- 消息的延迟发送等。
总结
这5种阻塞队列的特性各不相同,在使用的时候该怎么选择呢?我做了一张图,供大家参考。
图片