💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
- 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老
- 导航
- 檀越剑指大厂系列:全面总结 java 核心技术点,如集合,jvm,并发编程 redis,kafka,Spring,微服务,Netty 等
- 常用开发工具系列:罗列常用的开发工具,如 IDEA,Mac,Alfred,electerm,Git,typora,apifox 等
- 数据库系列:详细总结了常用数据库 mysql 技术点,以及工作中遇到的 mysql 问题等
- 懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
- 数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨
博客目录
- 一.Queue 介绍
- 1.Queue 的介绍
- 2.队列类图
- 3.Queue 的核心方法
- 4.Queue 的实现类
- 5.常见 Queue 说明
- 二.Deque 接口
- 1.什么是 Deque?
- 2.双端可用 Deque 接口
- 3.Deque 方法
- 4.Deque 和 Queue 比较
- 5.Deque 和 Stack 比较
- 6.Deque 的实现与继承
- 三.AbstractQueue 类
- 1.AbstractQueue 类介绍
- 2.AbstractQueue 的方法
- 3.AbstractQueue 的继承
- 四.BlockingQueue 接口
- 1.BlockingQueue 接口定义
- 2.BlockingQueue 核心方法
- 3.十个核心方法总结如下
- 4.BlockingQueue 原理
- 5.BlockingQueue 继承与实现
- 6.BlockingDeque 接口方法
- 五.TransferQueue 接口
- 1.TransferQueue 简介
- 2.理解三个方法
- 3.TransferQueue 的原理解析
- 4.TransferQueue 接口实现与继承
- 六.PriorityQueue 类
- 1.什么是 PriorityQueue?
- 2.PriorityQueue 特点
- 3.PriorityQueue 继承与实现
- 七.并发安全 Queue
- 1.ConcurrentLinkedQueue 图解
- 2.ConcurrentLinkedQueue 原理
- 3.ConcurrentLinkedDeque 类
- 4.ArrayBlockingQueue 类
- 5.LinkedBlockingQueue 类
- 6.LinkedBlockingDeque 类
- 7.PriorityBlockingQueue 类
- 八.其他 Queue
- 1.ArrayDeque 类
- 2.LinkedTransferQueue 类
- 3.SynchronousQueue 类
- 4.DelayQueue 类
一.Queue 介绍
1.Queue 的介绍
Queue
,中文名叫队列
,无论现实生活中还是计算机的世界中,都是一个很重要的角色哦~
Queue 是一种数据结构
,大家可以把我想象成一个数组,元素从我的一头进入、从另外一头出去,称为 FIFO 原则(先进先出原则)。
Queue 有两个亲兄弟:List
(列表)、Set
(集),他们都是Collection
的儿子,Queue 还有一个远房亲戚:Map
(映射)。他们都是java.util
包这个大家庭的成员哦~
2.队列类图
18 个 Queue 的继承实现关系图
-
Queue
接口继承Collection
接口,Collection
接口继承Iterable
接口 -
BlockingQueue
接口、Deque
接口 继承Queue
接口 -
AbstractQueue
抽象类实现Queue
接口 -
BlockingDeque
接口、TransferQueue
接口继承BlockingQueue
接口 -
BlockingDeque
接口继承Deque
接口 -
LinkedBlockingDeque
类实现BlockingDeque
接口 -
LinkedTransferQueue
类接口实现TransferQueue
接口 -
LinkedList
类、ArrayDeque
类、ConcurrentLinkedDeque
类实现 了Deque
接口 -
ArrayBlockingQueue
类、LinkendBlockingQueue
类、LinkedBlockingDeque
类、LinkedTransferQueue
类、SynchronousQueue
类、PriorityBlockQueue
类、DelayQueue类
继承 了AbstractQueue
抽象类和实现了 BlockingQueue 接口 -
PriorityQueue
类和ConcurrentLinkedQueue
类继承 了AbstractQueue
抽象类
注意:
- Deque:全称 Double-Ended queue,表示双端队列。
- 类实现接口,用 implements
- 接口继承接口,用 extends
- 类继承类,用 extends
3.Queue 的核心方法
- add
- element
- offer
- peek
- poll
- remove
Queue的核心方法:
动作 | 抛异常 | 返回特殊值 |
Insert | add(e) | offer(e) |
Remove | remove() | poll |
Examine | element() | peek() |
- 比如
添加(Insert)
元素的动作,会有两种方式:add(e)
和offer(e)
。如果调用 add(e)方法时,添加失败,则会抛异常
,而如果调用的是 offer(e)方法失败时,则会返回false
。offer 方法用于异常是正常的情况下使用,比如在有界队列中,优先使用 offer 方法。假如队列满了,不能添加元素,offer 方法返回 false,这样我们就知道是队列满了,而不是去 handle 运行时抛出的异常。 - 同理,移除(Remove)元素的动作,队列为空时,remove 方法抛异常,而 poll 返回 null。如果移除头部的元素成功,则返回移除的元素。
- 同理,检测(Examine)元素的动作,返回头部元素(最开始加入的元素),但不删除元素, 如果队列为空,则 element()方法抛异常,而 peek()返回 false。
- Queue 接口没有定义阻塞队列的方法,这些方法在 BlockQueue 接口中定义了。
- Queue 实现类通常不允许插入 null 元素,尽管一些实现类比如 LinkedList 不禁止插入 null,但是还是不建议插入 null,因为 null 也被用在 poll 方法的特殊返回值,以说明队列不包含元素。
4.Queue 的实现类
5.常见 Queue 说明
二.Deque 接口
1.什么是 Deque?
Queue 以及 Deque 都是继承于 Collection,Deque 是 Queue 的子接口。双端队列,可以在首尾插入或删除元素。
Deque 中直接子类有两个:LinkedList 以及 ArrayDeque。
ArrayDeque 是无初始容量的双端队列,LinkedList 则是双向链表。而我们还能看到,ArrayDeque 作为队列时的效率比 LinkedList 要高,而在栈的使用场景下,无疑具有尾结点不需判空的 LinkedList 较高效。
ArrayDeque 通常作为栈或队列使用,但是栈的效率不如 LinkedList 高。
LinkedList 通常作为栈或队列使用,但是队列的效率不如 ArrayQueue 高。
2.双端可用 Deque 接口
Deque 概念: 支持两端元素插入和移除的线性集合。名称deque
是双端队列的缩写,通常发音为deck
。大多数实现 Deque 的类,对它们包含的元素的数量没有固定的限制的,支持有界和无界。
3.Deque 方法
4.Deque 和 Queue 比较
作为 FIFO 时等价于 Queue 的方法如下表所示:
比如 Queue 的 add 方法和 Deque 的 addLast 方法等价。
5.Deque 和 Stack 比较
- Deque 也可以用作 LIFO(后进先出)栈,这个接口优于传统的 Stack 类。当作为栈使用时,元素被 push 到 deque 队列的头,而 pop 也是从队列的头 pop 出来。
- Stack(栈)的方法正好等同于 Deque 的如下方法:
注意:peek 方法不论是作为栈还是队列,都是从队列的检测队列的头,返回最先加入的元素。比如第一次 put 100,第二次 put 200,则 peek 返回的是 100。
6.Deque 的实现与继承
哪些类实现了Deque接口:
- LinkedList 类
- ArrayDeque 类
- ConcurrentLinkedDeque 类
- LinkedBlockingDeque 类
哪些类继承了Deque接口:
- BlockingDeque 接口
public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {}
三.AbstractQueue 类
1.AbstractQueue 类介绍
AbstractQueue 是一个抽象类,实现了 Queue 接口,提供了一些 Queue 操作的骨架实现。
public abstract class AbstractQueue<E>
extends AbstractCollection<E>
implements Queue<E> {
}
2.AbstractQueue 的方法
- add
- addAll
- clear
- element
- remove
方法 add、remove、element 方法基于 offer、poll 和 peek。也就是说如果不能正常操作,则抛出异常。
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
如果继承 AbstractQueue 抽象类则必须保证 offer 方法不允许 null 值插入。
3.AbstractQueue 的继承
哪些类继承了 AbstractQueue 抽象类:
-
ArrayBlockingQueue
类 -
LinkendBlockingQueue
类 -
LinkedBlockingDeque
类 -
LinkedTransferQueue
类 -
SynchronousQueue
类 -
PriorityBlockQueue
类 -
DelayQueue
类 -
PriorityQueue
类 -
ConcurrentLinkedQueue
类
四.BlockingQueue 接口
1.BlockingQueue 接口定义
阻塞队列:
- BlockQueue 满了,PUT 操作被阻塞
- BlockQueue 为空,Take 操作被阻塞
阻塞队列为空的情况:
- BlockingQueue(阻塞队列)也是一种队列,支持阻塞的插入和移除方法。
- 阻塞的插入:当队列满时,队列会阻塞插入元素的线程,直到队列不满。
- 阻塞的移除:当队列为空,获取元素的线程会等待队列变为非空。
- 应用场景:生产者和消费者,生产者线程向队列里添加元素,消费者线程从队列里移除元素,阻塞队列时获取和存放元素的容器。
- 为什么要用阻塞队列:生产者生产和消费者消费的速率不一样,需要用队列来解决速率差问题,当队列满了或空的时候,则需要阻塞生产或消费动作来解决队列满或空的问题。
2.BlockingQueue 核心方法
BlockingQueue 接口的 10 个核心方法:
3.十个核心方法总结如下
BlockingQueue接口的10个核心方法:
有三大类操作:插入、移除、检查。
- 插入有四种方法: add、offer、put、offer 超时版。
-
IllegalStateException
- 队列满了 -
ClassCastException
- 添加的元素类型不匹配 -
NullPointerException
- 添加的元素为 null -
IllegalArgumentException
- 添加的元素某些属性不匹配 - add 方法特别之处用于添加失败时抛出异常,共有四种异常:
- offer 方法特别之处用于添加失败时只返回 false
- put 方法特别之处用于当阻塞队列满时,生产者如果往队列里 put 元素,则队列会一直阻塞生产者线程,直到队列可用或者响应中断退出
- offer 超时方法特别之处用于当阻塞队列满时,生产者如果往队列里面插入元素,队列会阻塞生产者线程一段时间,如果超过了指定时间,生产者线程会退出,并返回 false。
- 移除有四种方法: remove、poll、take、poll 超时版
-
NoSuchElementException
- 如果这个队列是空的 - remove 方法特别之处用于移除失败时抛出异常
- poll 方法特别之处用于移除失败时返回 null
- take 方法特别之处用于当阻塞队列为空时,消费者线程如果从队列里面移除元素,则队列会一直阻塞消费者线程,直到队列不为空
- poll 超时方法特别之处用于当阻塞队列空时,消费者如果从队列里面删除元素,则队列会一直阻塞消费者线程,如果超过了指定时间,消费者线程会退出,并返回 null
- 检查有两种方法: element、peek
- element 方法用于检测头部元素的存在性,如果队列为空,则抛出异常,否则返回头部元素。
- peek 方法用于检测头部元素的存在性,如果队列为空,返回特殊值 null,否则返回头部的元素。
4.BlockingQueue 原理
BlockingQueue 通过什么来阻塞插入和移除的?
- 当往队列里插入一个元素时,如果队列不可用,那么阻塞生产者主要通过 LockSupport. park(this)来实现。
- park 这个方法会阻塞当前线程,只有以下 4 种情况中的一种发生时,该方法才会返回。
- 与 park 对应的 unpark 执行或已经执行时。“已经执行”是指 unpark 先执行,然后再执行 park 的情况。
- 线程被中断时。
- 等待完 time 参数指定的毫秒数时。
- 异常现象发生时,这个异常现象没有任何原因。
5.BlockingQueue 继承与实现
哪些类继承了BlockingQueue接口:
- BlockingDeque 接口 - 双端阻塞队列
- TransferQueue 接口 - 传输队列
哪些类实现了BlockingQueue接口:
- ArrayBlockingQueue 类 - 由数组构成的有界阻塞队列
- LinkedBlockingQueue 类 - 由链表构成的有界阻塞队列,界限默认大小为 Integer.MAX_Value(2^31-1),值非常大,相当于无界。
- LinkedBlockingDeque 类 - 由链表构成的双向阻塞队列
- LinkedTransferQueue 类 - 由链表构成的无界阻塞队列
- SynchronousQueue 类 - 不存储元素的阻塞队列,只有一个元素进行数据传递。
- LinkedTransferQueue 类 - 由链表构成的无界阻塞 TransferQueue 队列
- DelayQueue 类 - 使用优先级队列实现的延迟无界阻塞队列
6.BlockingDeque 接口方法
是阻塞队列BlockingQueue
和双向队列Deque
接口的结合。有如下方法:
BlockingQueue和BlockingDeque的对等方法:
五.TransferQueue 接口
1.TransferQueue 简介
如果有消费者正在获取元素,则将队列中的元素传递给消费者。如果没有消费者,则等待消费者消费。我把它称作使命必达队列,必须将任务完成才能返回。
2.理解三个方法
针对TransferQueue的transfer方法:
圆通快递员要将小明的 2 个快递送货到门,韵达快递员也想将小明的 2 个快递送货到门。小明一次只能拿一个,快递员必须等小明拿了一个后,才能继续给第二个。
针对TransferQueue的tryTransfer方法:
圆通快递员要将小明的 2 个快递送货到门,韵达快递员也想将小明的 2 个快递送货到门。发现小明不在家,就把快递直接放到菜鸟驿站了。
针对TransferQueue的tryTransfer超时方法:
圆通快递员要将小明的 2 个快递送货到门,韵达快递员也想将小明的 2 个快递送货到门。发现小明不在家,于是先等了 5 分钟,发现小明还没有回来,就把快递直接放到菜鸟驿站了。
3.TransferQueue 的原理解析
transfer方法的原理:
- 原理图解释:生产者线程 Producer Thread 尝试将元素 B 传给消费者线程,如果没有消费者线程,则将元素 B 放到尾节点。并且生产者线程等待元素 B 被消费。当元素 B 被消费后,生产者线程返回。
- 如果当前有消费者正在等待接收元素(消费者通过 take 方法或超时限制的 poll 方法时),transfer 方法可以把生产者传入的元素立刻 transfer(传输)给消费者。
- 如果没有消费者等待接收元素,transfer 方法会将元素放在队列的 tail(尾)节点,并等到该元素被消费者消费了才返回。
tryTransfer(E e)
- 试探生产者传入的元素是否能直接传给消费者。
- 如果没有消费者等待接收元素,则返回 false。
- 和 transfer 方法的区别是,无论消费者是否接收,方法立即返回。
tryTransfer(E e, long timeout, TimeUnit unit)
- 带有时间限制的 tryTransfer 方法。
- 试图把生产者传入的元素直接传给消费者。
- 如果没有消费者消费该元素则等待指定的时间再返回。
- 如果超时了还没有消费元素,则返回 false。
- 如果在超时时间内消费了元素,则返回 true。
getWaitingConsumerCount()
- 获取通过 BlockingQueue.take()方法或超时限制 poll 方法等待接受元素的消费者数量。近似值。
- 返回等待接收元素的消费者数量。
hasWaitingConsumer()
- 获取是否有通过 BlockingQueue.tabke()方法或超时限制 poll 方法等待接受元素的消费者。
- 返回 true 则表示至少有一个等待消费者。
4.TransferQueue 接口实现与继承
TransferQueue接口继承了哪些接口:
- BlockingQueue 接口,可作为阻塞队列使用
- Queue 接口,可作为队列使用
哪些类实现了TransferQueue接口:
- LinkedTranferQueue 接口
六.PriorityQueue 类
1.什么是 PriorityQueue?
队列是遵循先进先出(First-In-First-Out)模式的,但有时需要在队列中基于优先级处理对象。
Queue 有一个直接子类 PriorityQueue
PriorityQueue 是基于优先堆的一个无界队列,这个优先队列中的元素可以默认自然排序或者通过提供的 Comparator(比较器)在队列实例化的时排序。
- 优先队列的头是基于自然排序或者 Comparator 排序的最小元素。如果有多个对象拥有同样的排序,那么就可能随机地取其中任意一个。当我们获取队列时,返回队列的头对象。
- 优先队列的大小是不受限制的,但在创建时可以指定初始大小。当我们向优先队列增加元素的时候,队列大小会自动增加。
- PriorityQueue 是非线程安全的,所以 Java 提供了 PriorityBlockingQueue(实现 BlockingQueue 接口)用于 Java 多线程环境。
PriorityQueue 的底层数据结构是数组,而无边界的形容,那么指明了 PriorityQueue 是自带扩容机制的,具体请看 PriorityQueue 的 grow 方法。
PriorityQueue 可以作为堆使用,而且可以根据传入的 Comparator 实现大小的调整,会是一个很好的选择。
2.PriorityQueue 特点
按照自定义优先级排序
- PriorityQueue 是一个支持优先级的无界阻塞队列;
- 默认自然顺序升序排序;
- 可以通过构造参数 Comparator 来对元素进行排序;
- 自定义实现 comapreTo()方法来指定元素排序规则。
- 不允许插入 null 元素。
- 实现 PriorityQueue 接口的类,不保证线程安全,除非是 PriorityBlockingQueue。
- PriorityQueue 的迭代器不能保证以任何特定顺序遍历元素,如果需要有序遍历,请考虑使用
Arrays.sort(pq.toArray)
。 - 进列(
offer
、add
)和出列(poll
、remove()
)的时间复杂度 O(log(n))。 - remove(Object) 和 contains(Object)的算法时间复杂度 O(n)。
- peek、element、size 的算法时间复杂度为 O(1)。
public PriorityQueue(Comparator<? super E> comparator) {
this(DEFAULT_INITIAL_CAPACITY, comparator);
}
3.PriorityQueue 继承与实现
PriorityQueue类继承了哪些类:
- AbstractQueue 抽象类,具有队列的功能
PriorityQueue类实现了哪些接口:
- Queue 接口,可作为队列使用。
七.并发安全 Queue
1.ConcurrentLinkedQueue 图解
2.ConcurrentLinkedQueue 原理
- ConcurrentLinked 是由链表结构组成的线程安全的先进先出无界队列。
- 当多线程要共享访问集合时,ConcurrentLinkedQueue 是一个比较好的选择。
- 不允许插入 null 元素
- 支持非阻塞地访问并发安全的队列,不会抛出 ConcurrentModifiationException 异常。
- size 方法不是准确的,因为在统计集合的时候,队列可能正在添加元素,导致统计不准。
- 批量操作 addAll、removeAll、retainAll、containsAll、equals 和 toArray 不保证原子性(操作不可分割)
- 添加元素 happen-before 其他线程移除元素。
用法如下:
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
BuildingBlockWithName buildingBlock = new BuildingBlockWithName("三角形", "A");
concurrentLinkedQueue.add(buildingBlock);
继承与实现
ConcurrentLinkedQueue 类继承了哪些类
- AbstractQueue 抽象类,具有队列的功能
ConcurrentLinkedQueue 类实现了哪些接口
- Queue 接口,可作为队列使用
3.ConcurrentLinkedDeque 类
ConcurrentLinkedDeque原理图:
- 由链表结构组成的双向无界阻塞队列
- 插入、删除和访问操作可以并发进行,线程安全的类
- 不允许插入 null 元素
- 在并发场景下,计算队列的大小是不准确的,因为计算时,可能有元素加入队列。
- 批量操作 addAll、removeAll、retainAll、containsAll、equals 和 toArray 不保证原子性(操作不可分割)
使用:
BuildingBlockWithName buildingBlock1 = new BuildingBlockWithName("三角形", "A");
BuildingBlockWithName buildingBlock2 = new BuildingBlockWithName("四边形", "B");
ConcurrentLinkedDeque concurrentLinkedDeque = new ConcurrentLinkedDeque();
concurrentLinkedDeque.addFirst(buildingBlock1);
concurrentLinkedDeque.addLast(buildingBlock2);
//结果:顺序:三角形、四边形
4.ArrayBlockingQueue 类
ArrayBlockingQueuey原理:
- ArrayBlockingQueue 是一个用数组实现的有界阻塞队列。
- 队列慢时插入操作被阻塞,队列空时,移除操作被阻塞。
- 按照先进先出(FIFO)原则对元素进行排序。
- 默认不保证线程公平的访问队列。
- 公平访问队列:按照阻塞的先后顺序访问队列,即先阻塞的线程先访问队列。
- 非公平性是对先等待的线程是非公平的,当队列可用时,阻塞的线程都可以争夺访问队列的资格。有可能先阻塞的线程最后才访问访问队列。
- 公平性会降低吞吐量。
使用:
创建两个积木:三角形、四边形,然后添加到队列:
BuildingBlockWithName buildingBlock1 = new BuildingBlockWithName("三角形", "A");
BuildingBlockWithName buildingBlock2 = new BuildingBlockWithName("四边形", "B");
ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(100, true);
arrayBlockingQueue.add(buildingBlock1);
arrayBlockingQueue.add(buildingBlock2);
5.LinkedBlockingQueue 类
LinkedBlockingQueue原理:
- LinkedBlockingQueue 具有单链表和有界阻塞队列的功能。
- 队列慢时插入操作被阻塞,队列空时,移除操作被阻塞。
- 默认和最大长度为 Integer.MAX_VALUE,相当于无界(值非常大:2^31-1)。
LinkedBlockingQueue的应用场景:
- 吞吐量通常要高于 ArrayBlockingQueue。创建线程池时,参数 runnableTaskQueue(任务队列),用于保存等待执行的任务的阻塞队列可以选择 LinkedBlockingQueue。静态工厂方法 Executors.newFixedThreadPool()使用了这个队列。
LinkedBlockingQueue实现了哪些接口:
- LinkedBlockingQueue 继承了 BlockingQueue 类,可作为阻塞队列使用
- LinkedBlockingQueue 继承了 AbstractQueue 抽象类,具有队列的功能。
- LinkedBlockingQueue 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。
6.LinkedBlockingDeque 类
LinkedBlockingDeque原理:
- 由链 LinkedBlockingDeque = 阻塞队列+链表+双端访问
- 线程安全。
- 多线程同时入队时,因多了一端访问入口,所以减少了一半的竞争。
- 默认容量大小为 Integer.MAX_VALUE。可指定容量大小。
LinkedBlockingDeque的应用场景:
LinkedBlockingDeque 可以用在“工作窃取“模式中。
工作窃取算法
:某个线程比较空闲,从其他线程的工作队列中的队尾窃取任务来帮忙执行。
LinkedBlockingDeque实现了哪些接口:
- LinkedBlockingDeque 继承了 BlockingDeque 类,可作为阻塞队列使用
- LinkedBlockingDeque 继承了 AbstractQueue 抽象类,具有队列的功能。
- LinkedBlockingDeque 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。
7.PriorityBlockingQueue 类
PriorityBlockQueue的原理:
- PriorityBlockQueue = PriorityQueue + BlockingQueue
- 之前我们也讲到了 PriorityQueue 的原理,支持对元素排序。
- 元素默认自然排序。
- 可以自定义 CompareTo()方法来指定元素排序规则。
- 可以通过构造函数构造参数 Comparator 来对元素进行排序。
PriorityBlockQueue实现了哪些接口:
- LinkedBlockingQueue 继承了 BlockingQueue 接口,可作为阻塞队列使用
- LinkedBlockingQueue 继承了 AbstractQueue 抽象类,具有队列的功能。
- LinkedBlockingQueue 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。
八.其他 Queue
1.ArrayDeque 类
特点:
- 由数组组成的双端队列。
- 没有容量限制,根据需要扩容。
- 不是线程安全的。
- 禁止插入 null 元素。
- 当用作栈时,比栈速度快,当用作队列时,速度比 LinkList 快。
- 大部分方法的算法时间复杂度为 O(1)。
- remove、removeFirstOccurrence、removeLastOccurrence、contains、remove 和批量操作的算法时间复杂度 O(n)
使用:
ArrayDeque arrayDeque = new ArrayDeque();
for (int i = 0; i < 50; i++) {
arrayDeque.add(buildingBlock); // add方法等价于addLast方法
}
2.LinkedTransferQueue 类
LinkedTransferQueue原理:
LinkedTransferQueue = 阻塞队列+链表结构+TransferQueue
之前我们讲“使命必达 TransferQueue 接口时已经介绍过了 TransferQueue 接口 ,所以 LinkedTransferQueue 接口跟它相似,只是加入了阻塞插入和移除的功能,以及结构是链表结构。
之前的 TransferQueue 也讲到了 3 个案例来说明 TransferQueue 的原理,大家可以回看 TransferQueue。
LinkedTransferQueue接口比其他阻塞队列多了5个方法:
- transfer(E e)
- tryTransfer(E e)
- tryTransfer(E e, long timeout, TimeUnit unit)
- getWaitingConsumerCount()
- hasWaitingConsumer()
LinkedTransferQueue实现了哪些接口:
- LinkedBlockingDeque 继承了 BlockingQeque 类,可作为阻塞队列使用
- LinkedBlockingDeque 继承了 AbstractQueue 抽象类,具有队列的功能
3.SynchronousQueue 类
SynchronousQueue原理:
- 我称 SynchronousQueue 为”传球好手“。想象一下这个场景:小明抱着一个篮球想传给小花,如果小花没有将球拿走,则小明是不能再拿其他球的。
- SynchronousQueue 负责把生产者产生的数据传递给消费者线程。
- SynchronousQueue 本身不存储数据,调用了 put 方法后,队列里面也是空的。
- 每一个 put 操作必须等待一个 take 操作完成,否则不能添加元素。
- 适合传递性场景。
- 性能高于 ArrayBlockingQueue 和 LinkedBlockingQueue。
SynchronousQueue应用场景:
- 吞吐量通常要高于 LinkedBlockingQueue。创建线程池时,参数 runnableTaskQueue(任务队列),用于保存等待执行的任务的阻塞队列可以选择 SynchronousQueue。静态工厂方法 Executors.newCachedThreadPool()使用了这个队列
SynchronousQueue和LinkedTransferQueue的区别:
- SynchronousQueue 不存储元素,而 LinkedTransferQueue 存储元素。
- SynchronousQueue 队列里面没有元素,而 LinkedTransferQueue 可以有多个存储在队列等待传输。
- LinkedTransferQueue 还支持若传输不了,则丢到队列里面去。
- LinkedTransferQueue 还支持若超过一定时间传输不了,则丢到队列里面去。
4.DelayQueue 类
DelayQueue原理:
- DelayQueue = Delayed + BlockingQueue。队列中的元素必须实现 Delayed 接口。
- 在创建元素时,可以指定多久可以从队列中获取到当前元素。只有在延时期满才能从队列中获取到当前元素。
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E> {
源码解析:
- 添加元素时,指定延时多久可以从队列中获取元素
public boolean offer(E e, long timeout, TimeUnit unit) {
return offer(e);
}
- 获取元素的方法 poll 需要等待延时时间过了才能获取到元素
if (first == null || first.getDelay(NANOSECONDS) > 0)
return null;
else
return q.poll();
应用场景:
- 缓存系统的设计:可以用 DelayQueue 保存缓存元素的有效期。然后用一个线程循环的查询 DelayQueue 队列,一旦能从 DelayQueue 中获取元素时,表示缓存有效期到了。
- 定时任务调度:使用 DelayQueue 队列保存当天将会执行的任务和执行时间,一旦从 DelayQueue 中获取到任务就开始执行。比如 Java 中的 TimerQueue 就是使用 DelayQueue 实现的。
DelayQueue实现了哪些接口:
- DelayQueue 实现了 BlockingQueue 接口,可作为阻塞队列使用
觉得有用的话点个赞
👍🏻
呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙