本篇主要内容如下:
本篇主要内容
帮你总结好的阻塞队列:
18种Queue总结
队列原理图
hi,大家好,我的英文名叫Queue
,中文名叫队列
,无论现实生活中还是计算机的世界中,我都是一个很重要的角色哦~
我是一种数据结构
,大家可以把我想象成一个数组,元素从我的一头进入、从另外一头出去,称为FIFO原则(先进先出原则)。
我还有两个亲兄弟:List
(列表)、Set
(集),他们都是Collection
的儿子,我还有一个远房亲戚:Map
(映射)。他们都是java.util
包这个大家庭的成员哦~
18种队列分为三大类: 接口、抽象类、普通类。
弄清楚下面的继承实现关系对后面理解18种队列有很大帮助。
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
抽象类注意:
总共有3组方法,每一组方法对应两个方法。如下图所示:
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运行时抛出的异常。双端队列Deque
(1)Deque概念: 支持两端元素插入和移除的线性集合。名称deque
是双端队列的缩写,通常发音为deck
。大多数实现Deque的类,对它们包含的元素的数量没有固定的限制的,支持有界和无界。
(2)Deque方法说明:
Deque方法
说明:
比如Queue的add方法和Deque的addLast方法等价。
Deque也可以用作LIFO(后进先出)栈,这个接口优于传统的Stack类。当作为栈使用时,元素被push到deque队列的头,而pop也是从队列的头pop出来。
Stack(栈)的方法正好等同于Deque的如下方法:
注意:peek方法不论是作为栈还是队列,都是从队列的检测队列的头,返回最先加入的元素。比如第一次put 100,第二次put 200,则peek返回的是100。如下图所示:
示例代码
AbstractQueue是一个抽象类,继承了Queue接口,提供了一些Queue操作的骨架实现。
AbstractQueue的方法
方法add、remove、element方法基于offer、poll和peek。也就是说如果不能正常操作,则抛出异常。我们来看下AbstactQueue是怎么做到的。
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
public E remove() {
E x = poll();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
public E element() {
E x = peek();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
注意:
ArrayBlockingQueue
类、LinkendBlockingQueue
类、LinkedBlockingDeque
类、LinkedTransferQueue
类、SynchronousQueue
类、PriorityBlockQueue
类、DelayQueue类
继承 了AbstractQueue
抽象类PriorityQueue
类和ConcurrentLinkedQueue
类继承 了AbstractQueue
抽象类阻塞队列满了的情况
阻塞队列为空的情况
(1)BlockingQueue(阻塞队列)也是一种队列,支持阻塞的插入和移除方法。
(3)阻塞的插入:当队列满时,队列会阻塞插入元素的线程,直到队列不满。
(4)阻塞的移除:当队列为空,获取元素的线程会等待队列变为非空。
(5)应用场景:生产者和消费者,生产者线程向队列里添加元素,消费者线程从队列里移除元素,阻塞队列时获取和存放元素的容器。
(6)为什么要用阻塞队列:生产者生产和消费者消费的速率不一样,需要用队列来解决速率差问题,当队列满了或空的时候,则需要阻塞生产或消费动作来解决队列满或空的问题。
线程A往阻塞队列(Blocking Queue)中添加
元素,而线程B从阻塞队列中移除
元素。
当阻塞队列为空的时候 (一个元素都没有),则从队列中获取元素的操作将会被阻塞。
生活中的案例:去海底捞吃火锅的时候,早上8点没人来吃火锅,所以需要等客人过来。
翻译成线程:现在没有元素需要添加,而且阻塞队列为空,所以线程B不需要从队列中拿元素出来,所以线程B获取元素的操作被阻塞了。
当阻塞队列满了的时候 (所有位置都放有元素),则从队列中添加元素的操作将会被阻塞。
生活中的案例:去海底捞吃火锅的时候,人太多了,需要排号,等其他桌空出来了才能进去。
翻译成线程:线程A往阻塞队列中添加元素,将队列填满了,线程B现在正在忙,无法拿出队列中的元素,所以阻塞队列没有地方再放元素了,这个时候线程A添加元素的操作就被阻塞了
BlockingQueue接口的10个核心方法:
继承的方法
10个核心方法总结如下:
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,否则返回头部的元素。
BlockingDeque满了
BlockQueue为空
是阻塞队列BlockingQueue
和双向队列Deque
接口的结合。有如下方法:
BlockingDeque接口方法
示例:
尝试执行以下方法:
LinkedBlockingDeque queue = new LinkedBlockingDeque();
queue.addFirst("test1");
queue.addFirst(300);
queue.addLast("400");
最后队列中的元素顺序如下:
300, test1, 400。
先添加了test1放到队列的头部,然后在头部的前面放入300,所以300在最前面,成为头部,然后将400放入队列的尾部,所以最后的结果是300, test1, 400。
队列种的元素
BlockDeque和BlockQueue的对等方法
如果有消费者正在获取元素,则将队列中的元素传递给消费者。如果没有消费者,则等待消费者消费。我把它称作使命必达队列,必须将任务完成才能返回。
针对TransferQueue的transfer方法
圆通快递员要将小明的2个快递送货到门,韵达快递员也想将小明的2个快递送货到门。小明一次只能拿一个,快递员必须等小明拿了一个后,才能继续给第二个。
针对TransferQueue的tryTransfer方法
圆通快递员要将小明的2个快递送货到门,韵达快递员也想将小明的2个快递送货到门。发现小明不在家,就把快递直接放到菜鸟驿站了。
针对TransferQueue的tryTransfer超时方法
圆通快递员要将小明的2个快递送货到门,韵达快递员也想将小明的2个快递送货到门。发现小明不在家,于是先等了5分钟,发现小明还没有回来,就把快递直接放到菜鸟驿站了。
transfer(E e)
原理如下图所示:
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则表示至少有一个等待消费者。
本应该按照升序排序
按照自定义优先级排序
public PriorityQueue(Comparator<? super E> comparator) {
this(DEFAULT_INITIAL_CAPACITY, comparator);
}
public Comparator<? super E> comparator() {
return comparator;
}
Arrays.sort(pq.toArray)
。offer
、add
)和出列( poll
、remove()
)的时间复杂度O(log(n))。LinkedList的结构
我们来看下节点类Node
private static class Node<E> {
E item; //元素
Node<E> next; //向后的节点链接
Node<E> prev; //向前的节点链接
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
1.LinkedList的增加和删除效率相对较高,而查找和修改的效率相对较低。
2.以下情况建议使用ArrayList
频繁访问列表中的一个元素。
只在列表的首尾添加元素。
3.以下情况建议使用LinkedList
频繁地在列表开头、中间、末尾添加和删除元素。
需要通过循环迭代来访问列表中的元素。
LinkedList不是线程安全的,所以可以使用如下方式保证线程安全。
List list = Collections.synchronizedList(new LinkedList<>());
ConcurrentLinkedQueue原理
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
BuildingBlockWithName buildingBlock = new BuildingBlockWithName("三角形", "A");
concurrentLinkedQueue.add(buildingBlock);
ArrayDeque原理图
创建一个ArrayDeque,往arrayDeque队尾添加元素。
ArrayDeque arrayDeque = new ArrayDeque();
for (int i = 0; i < 50; i++) {
arrayDeque.add(buildingBlock); // add方法等价于addLast方法
}
ConcurrentLinkedDeque原理图
创建两个积木:三角形、四边形,然后添加到队列:
BuildingBlockWithName buildingBlock1 = new BuildingBlockWithName("三角形", "A");
BuildingBlockWithName buildingBlock2 = new BuildingBlockWithName("四边形", "B");
ConcurrentLinkedDeque concurrentLinkedDeque = new ConcurrentLinkedDeque();
concurrentLinkedDeque.addFirst(buildingBlock1);
concurrentLinkedDeque.addLast(buildingBlock2);
//结果:顺序:三角形、四边形
ArrayBlockingQueuey原理图
创建两个积木:三角形、四边形,然后添加到队列:
BuildingBlockWithName buildingBlock1 = new BuildingBlockWithName("三角形", "A");
BuildingBlockWithName buildingBlock2 = new BuildingBlockWithName("四边形", "B");
ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(100, true);
arrayBlockingQueue.add(buildingBlock1);
arrayBlockingQueue.add(buildingBlock2);
LinkedBlockingQueue原理
LinkedList linkedList1 = new LinkedList();
linkedList1.add("A");
linkedList1.add("B");
linkedList1.add("C");
LinkedBlockingDeque原理图
LinkedBlockingDeque可以用在“工作窃取“模式中。
工作窃取算法
:某个线程比较空闲,从其他线程的工作队列中的队尾窃取任务来帮忙执行。
LinkedTransferQueue原理图
LinkedTransferQueue = 阻塞队列+链表结构+TransferQueue
之前我们讲“使命必达TransferQueue接口时已经介绍过了TransferQueue接口 ,所以LinkedTransferQueue接口跟它相似,只是加入了阻塞插入和移除的功能,以及结构是链表结构。
之前的TransferQueue也讲到了3个案例来说明TransferQueue的原理,大家可以回看TransferQueue。
生产者1 依次往队列中添加 A、B、C
生产者2 依次往队列中添加 D、E、F
消费者消费元素
生产者1 transfer A
生产者2 transfer D
2s后...
消费者 take A
生产者1 put B
2s后...
消费者 take D
生产者2 transfer E
2s后...
消费者 take B
生产者1 transfer C
(1)首先生产者线程1和2 调用transfer方法来传输A和D,发现没有消费者线程接收,所以被阻塞。
(2)消费者线程过了2s后将A拿走了,然后生产者1 被释放继续执行,传输元素B,发现又没有消费者消费,所以进行了等待。
(3)消费者线程过了2s后,将排在队列首部的D元素拿走,生产者2继续往下执行,传输元素E,发现没有消费者,所以进行了等待。
(4)消费者线程过了2s后,将排在队列首部的B元素拿走,生产者1传输C元素,等待消费者拿走。
(5)消费者不再消费了,所以生产者1和生产者2都被阻塞了,元素C和,元素E都没有被拿走,而且生产者2的F元素还没有开始传输,因为在等待元素D被拿走。
(6)看下队列里面确实有C和E元素,而且E排在队列的首部。
队列里面的元素
SynchronousQueue原理图
我们创建了两个线程,一个线程用于生产,一个线程用于消费
生产的线程依次put A、B、C三个值
消费线程每隔5s调用take方法
t1 put A
t2 take A
5秒后...
t1 put B
t2 take B
5秒后...
t1 put C
t2 take C
小结:说明生产线程执行put第一个元素"A" 操作后,需要等待消费者线程take完“A”后,才能继续往下执行代码。
PriorityBlockQueue的原理图
DelayQueue原理图
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E> {
public boolean offer(E e, long timeout, TimeUnit unit) {
return offer(e);
}
if (first == null || first.getDelay(NANOSECONDS) > 0)
return null;
else
return q.poll();
poll方法
这一篇花了很多心思在上面,看官方英文文档、画原理图、写demo代码,排版。这恐怕是市面上最全最细讲解Queue的。
- END -
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/Y-nIzZQIc4ynmegoUqoHMA
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。