目录
3.1. LinkedBlockingQueue/LinkedBlockingDeque
3.4. PriorityQueue/PriorityBlockingQueue
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是一个合适的选择。
文章介绍了Java中不同类型的队列,包括阻塞队列和非阻塞队列的概念,以及有界队列和无界队列的区别。重点讲解了各种实现类,如LinkedBlockingQueue、ArrayBlockingQueue、PriorityQueue、ConcurrentLinkedQueue等,它们的特性以及在并发环境下的应用。
1145

被折叠的 条评论
为什么被折叠?



