|一文总结常见阻塞队列

文章图片

今前面已经学习了主要的阻塞队列 , 今天对它们整体来一次梳理 。
类总结图先看下所有阻塞队列类在类图中的位置和继承结构 , 常见阻塞队列如下图:
上图已经把前面总结的阻塞队列的继承体系梳理出来了 , 之前学习的时候总是发现每个类继承一个类又实现了一个接口 , 然后父类的接口又继承或者实现 , 看上去很复杂 。 通过这个总结类图看上去就很简单了 。
上图中对每个类都进行了简单的总结 , 接下来详细说明他们的作用 。
抽象类与接口功能介绍首先是最顶层接口Iterable , 它有一个属性Iterator , 用来迭代元素 , Collection继承它 , 所以所有集合类都有属性Iterator , 可以遍历元素 。
接口Collection就不多做介绍了 , 是集合类的顶层接口 , 用来定义集合类一些基础方法比如size、add、remove、contaions、isEmpty等 , 这里也说明了所有的队列也是属于集合家族的 。
第三层是AbstractCollection抽象类和Queue接口 。
AbstractCollection实现了一些方法 , 由于到这一层还没有定义顶层存储数据的结构 , 所以是利用Iterator遍历元素来实现一些方法比如contains、toArray、remove、toString 。
而Queue接口则是定义了一些队列应该有的特征方法 , 比如poll、offer、peek 。
第四层是AbstractQueue抽象类与BlockingQueue接口 。
抽象类AbstractQueue继承了抽象类AbstractCollection , 通过总结图可以看到所有的阻塞队列都实现了AbstractQueue 。 主要作用是把集合的特征进行队列化 , 主要是把add方法调用offer方法实现 , remove用poll实现 , 通过这样处理虽然所有队列都是集合 , 但是并不会影响队列的特征 , AbstractQueue还通过peek方法实现了element方法 。
BlockingQueue接口则是声明阻塞队列的特征方法 , 主要是take、put , 还有offer和poll的延时方法 。
其他几个类Deque接口 , 它继承Queue , 是队列中的特殊队列:双向队列 , 所以Deque中主要是把Queue的出队入队方法基础上扩展了First、Last结尾的方法 , 表示可以从头部、尾部进行入队或者出队操作 。
BlockingDeque则是对Deque往阻塞方向的扩展 , 也就是声明了阻塞队列拥有的take、put , 还有offer和poll的延时方法以及他们的First、Last结尾的方法 。
TransferQueue继承BlockingQueue接口 , 主要是进行了transfer扩展 , 新声明了transfer、tryTransfer方法 , transfer方法会一直阻塞直到添加的数据被消费者消费 。
DelayQueue队列中存储的元素必须实现Delayed接口 , 他主要有一个getDelay方法 , 可以理解成元素还是多长时间才能被消费 , 可以利用他来实现延迟执行 , 定时任务等功能 。
阻塞队列对比接下来对阻塞队列进行对比 , 这里对每个类不会进行详细的介绍 , 详情可以看前面几篇文章 , 这里只说明他们的特征方便与其他队列进行对比 , 主要特征如下:
ArrayBlockingQueue:底层实现数组、先入先出、有界队列 , 构造是需指定数组长度且不可变 , ReentrantLock、Condition实现线程安全;
LinkedBlockingQueue:底层实现链表 , 先入先出、无界队列 , ReentrantLock、Condition实现线程安全;
PriorityBlockingQueue:底层数组实现二叉堆 , 数组可变 , 所以是支持优先级无界阻塞队列 , ReentrantLock、Condition实现线程安全;
DelayQueue:底层数据是PriorityQueue(无锁无阻塞无界优先级队列) , ReentrantLock、Condition实现线程安全 , 保存元素必须实现Delayed接口 , 可以指定元素出队时间;
SynchronousQueue:没有容量 , 不管是take还是put进来的线程 , 如果没有匹配就阻塞 , 等待异类线程交换数据并唤醒 , 支持公平与非公平模式 , 无锁通过CAS实现;
LinkedTransferQueue:链表实现无界阻塞队列 , put方法不阻塞 , take方法先进可以占位置 , 后面的put会先给到它 , transfer方法与SynchronousQueue的公平模式一样 , 无锁通过CAS实现;
LinkedBlockingDeque:双向链表、无界阻塞队列 , 可实现先入先出、先入后出、优先进出 , ReentrantLock、Condition实现线程安全;
对比表格如图:
实际上除了ArrayBlockingQueue与LinkedBlockingQueue , 其他几个队列都有比较特殊的意义 , 所以对比的意义不大 。
ArrayBlockingQueue主要是需要初始化一个数组 , 如果要存储的元素很多则需要初始化的数组太大 , 那么太占内存 , 而LinkedBlockingQueue则不需要初始化一个存储数据的结构 , 保存一个元素创建一个节点 , 但是每个元素消耗的内存就更多 。
总结通过体系结构可以看出来接口都是声明一些特征用的 , 而抽象类则是实现接口的一些通用方法 , 或者能实现的方法 。
【|一文总结常见阻塞队列】可以通过一个我自己编的流程来记住这几个阻塞队列:
首先是实现了一个阻塞队列ArrayBlockingQueue , 但是我发现它总是需要初始化存储结构浪费内存 , 所以又实现了LinkedBlockingQueue , 不用初始化占用内存 , 有一个存一个;
后面又发现我虽然有些元素是先保存的 , 但是我想优先消费一些元素 , 所以就实现了一个优先级队列PriorityBlockingQueue 。 但是优先级有时候并不够 , 因为优先的原因是先执行 , 但是却还没有到我想执行的时间 , 所以实现了延迟队列DelayQueue来满足;
虽然把数据放到了队列中但是我并不确定一定被消费了 , 因为只有消费了我才行确定下一步 , 所以有实现了同步队列SynchronousQueue 。 但是同步队列又限制的太死 , 所以实现了LinkedTransferQueue , put方法不再阻塞 , 而是特有的方法transfer才保证一定消费 。
但是可能还有更加灵活的情况 , 有可能想最先被消费或者最后被消费 , 也有可能想消费前面的 , 或者消费最后面的 , 所以实现了LinkedBlockingDeque 。
Java程序员日常学习笔记 , 如理解有误欢迎各位交流讨论!
推荐阅读
- 肝癌|深度总结|慢乙肝抗病毒治疗中发生肝癌的风险预测模型
- 减肥|郭美美因减肥药再次入狱,细数市面上常见减肥药,减肥无捷径
- 这种野菜路边很常见,摘回家蒸一蒸,变身网红美食,松软又清香
- 血小板|4个常见生活小策略,专门对付血小板减少“病情反复”
- 糖尿病并发症|JMT日本常见病治疗-糖尿病并发症的原因和危险的三大并发症
- 面包店最常见的面包自己做,真材实料吃得放心,食材做法都简单
- 懒人营养早餐几种常见推荐,营养又方便
- 这道菜是超市里最常见的虽然是蔬菜,但比羊肉更有营养我每三五次吃一次
- 香味四溢的几道家常菜,食材常见做法简单,美味下饭,家人都爱吃
- 面包和馒头的区别是什么?看完这些总结,才知道自己一直没分清楚
