Java 之 Queue 家族

文章介绍了Java中不同类型的队列,包括阻塞队列和非阻塞队列的概念,以及有界队列和无界队列的区别。重点讲解了各种实现类,如LinkedBlockingQueue、ArrayBlockingQueue、PriorityQueue、ConcurrentLinkedQueue等,它们的特性以及在并发环境下的应用。

目录

一. 前言

二. 类型划分

2.1. 阻塞队列和非阻塞队列

2.2. 有界队列和无界队列

2.3. 单向链表和双向链表

三. 实现类

3.1. LinkedBlockingQueue/LinkedBlockingDeque

3.2. DelayQueue

3.3. ArrayBlockingQueue

3.4. PriorityQueue/PriorityBlockingQueue

3.5. LinkedTransferQueue

3.6. SynchronousQueue

3.7. ArrayDeque

3.8. ConcurrentLinkedQueue/ConcurrentLinkedDeque


一. 前言

       队列是一种特殊的线性表,遵循先入先出、后入后出的基本原则,一般来说,它只允许在表的前端进行删除操作,而在表的后端进行插入操作,但是java的某些队列允许在任何地方插入删除;比如我们常用的 LinkedList 集合,它实现了Queue 接口,因此,我们可以理解为 LinkedList 就是一个队列。

二. 类型划分

队列主要分为阻塞和非阻塞,有界和无界、单向链表和双向链表。

2.1. 阻塞队列和非阻塞队列

阻塞队列:入队(添加元素)时,如果元素数量超过队列总数,会进行等待(阻塞),待队列的中的元素出队后,元素数量未超过队列总数时,就会解除阻塞状态,进而可以继续入列;
       出队(删除元素)时,如果队列为空的情况下,也会进行等待(阻塞),待队列有值的时候即会解除阻塞状态,进而继续出队;
       阻塞队列的好处是可以防止队列容器溢出;只要满了就会进行阻塞等待;也就不存在溢出的情况;只要是阻塞队列,都是线程安全的。

非阻塞队列:不管出队还是入队,都不会进行阻塞,
       入队时,如果元素数量超过队列总数,则会抛出异常,
       出队时,如果队列为空,则取出空值;

一般情况下,非阻塞式队列使用的比较少,一般都用阻塞式的对象比较多;阻塞队列有:DelayQueue、LinkedTransferQueue、ArrayBlockingQueue、SynchronousQueue、PriorityBlockingQueue。非阻塞队列有:PriorityQueue、ConcurrentLinkedQueue、ConcurrentLinkedDeque。

2.2. 有界队列和无界队列

有界队列:有界限,大小长度受限制。
无界队列:无限大小,其实说是无限大小,其实是有界限的,只不过超过界限时就会进行扩容,就行ArrayList 一样,在内部动态扩容。

2.3. 单向链表和双向链表

单向链表: 每个元素中除了元素本身之外,还存储一个指针,这个指针指向下一个元素;

双向链表:除了元素本身之外,还有两个指针,一个指针指向前一个元素的地址,另一个指针指向后一个元素的地址; 

三. 实现类

3.1. LinkedBlockingQueue/LinkedBlockingDeque

LinkedBlockingQueue:是一个只能一端入一端出的单向队列结构,是有FIFO特性的,并且是通过两个ReentrantLock和两个Condition来实现的。和LinkedBlockingDeque的区别之一就是,LinkedBlockingQueue采用了两把锁来对队列进行操作,也就是队尾添加的时候,队头仍然可以删除等操作。

LinkedBlockingDeque:是一个双端队列,任何一端都可以进行元素的出入。

3.2. DelayQueue

一个使用优先级队列实现的无界阻塞队列。DelayQueue队列中每个元素都有一个过期时间,并且队列是个优先级队列,当从队列获取元素的时候,只有过期元素才会出队。

3.3. ArrayBlockingQueue

一个由数组结构组成的有界阻塞队列。其内部按先进先出的原则对元素进行排序,其中put方法和take方法为添加和删除的阻塞方法。

3.4. PriorityQueue/PriorityBlockingQueue

PriorityQueue是基于优先堆的一个无界队列,非线程安全的,默认情况下根据自然排序,当然我们也可以定制比较器,自行自定义排序,从而实现自己的优先级逻辑。

详情请参见《PriorityQueue 源码解析(JDK1.8)》

PriorityBlockingQueue是一个无界有序的阻塞队列,排序规则和之前介绍的PriorityQueue一致,只是增加了阻塞操作。同样的,该队列不支持插入null元素,同时不支持插入非comparable的对象。

3.5. LinkedTransferQueue

LinkedTransferQueue 链表实现的无界阻塞队列。相对于其他阻塞队列,LinkedTransferQueue多了tryTransfer和transfer方法。其使用一种预占的模式,当消费者获取元素的时候如果队列不为空则直接获取元素,如果队列为空,则生产一个null的元素,然后在这个节点上等待。当有新的线程添加元素的时候,如果发现有null的元素则直接唤醒消费线程取走元素。

3.6. SynchronousQueue

SynchronousQueue是一个不存储元素的阻塞队列,每个put操作必须等待一个take操作,否则不能添加元素,SynchronousQueue队列本身不存储任何元素,适合传递性场景,比如一个线程中的数据传递给另一个线程使用,它的吞吐量比LinkedBlockingQueue和ArrayBlockingQueue更好一些。

3.7. ArrayDeque

ArrayDeque是 Deque接口的一个实现,使用了可变数组,所以没有容量上的限制,不支持 null值。同时,ArrayDeque是线程不安全的,在没有外部同步的情况下,不能再多线程环境下使用。
ArrayDeque是 Deque的实现类,可以作为栈来使用,效率高于 Stack;也可以作为队列来使用,效率高于 LinkedList。
ArrayDeque是 Java 集合中双端队列的数组实现,双端队列的链表实现(LinkedList)。

详解请参见《ArrayDeque 源码解析(JDK1.8)》

3.8. ConcurrentLinkedQueue/ConcurrentLinkedDeque

ConcurrentLinkedQueue是一个单向链表结构的无界并发队列, 非阻塞队列,由CAS实现线程安全,内部基于节点实现,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部,当我们获取一个元素时,它会返回队列头部的元素。

ConcurrentLinkedDeque是一种双向链表结构的无界并发队列, 非阻塞队列,由CAS实现线程安全。可以安全地并发执行插入、删除和访问操作。当许多线程同时访问一个公共集合时,ConcurrentLinkedDeque是一个合适的选择。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流华追梦

你的鼓励将是我创作最大的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值