什么是队列?
队列是一种操作受限的线性表,只允许在表的前端(front)进行删除操作又称作出队,在表的后端进行插入操作,称为入队,符合先进先出(First in First out)的特性。在队尾插入元素叫做入队,对头删除元素叫做出队。
比如我们常用的 LinkedList 集合,它实现了Queue 接口,我们可以理解为 LinkedList 就是一个队列。
Java队列分类?
Java 队列可以从不同的维度进行分类,例如:可以从阻塞和非阻塞进行分类;也可以从有界和无界进行分类;也可以从功能上进行分类,例如:优先队列、普通队列、双端队列、延迟队列等。
具体分类如下图所示:
Java常用的队列?
1.阻塞队列
阻塞队列区别于其他类型的队列的最主要的特点就是“阻塞”这两个字,如下图所示:
阻塞功能使得生产者和消费者两端的能力得以平衡,当有任何一端速度过快时,阻塞队列便会把过快的速度给降下来。
阻塞队列大致可以分为如下7类:
1)ArrayBlockingQueue
ArrayBlockingQueue是一个用数组实现的 有界阻塞队列。 此队列按照先进先出(FIFO)的原则对元素进行排序。
2)LinkedBlockingQueue
LinkedBlockingQueue是一个用链表实现的 有界阻塞队列,此队列的默认和最大长度为Integer.MAX_VALUE,此队列按照先进先出的原则对元素进行排序。
3)PriorityBlockingQueue
PriorityBlockingQueue是一个带优先级的队列,而不是先进先出队列,元素按优先级顺序被移除,而且它是无界的,也就是没有容量上限。
虽然此队列逻辑上是无界的,但是由于资源被耗尽,所以试图执行添加操作可能会导致 OutOfMemoryError 错误;
4)DelayQueue
Delayed 元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素。注意 DelayQueue 的所有方法只能操作“到期的元素“。
我们可以将DelayQueue运用在以下应用场景:
- 缓存系统的设计:可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了;
- 定时任务调度:使用DelayQueue保存当天将会执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行,从比如TimerQueue就是使用DelayQueue实现的。
5)SynchronousQueue
SynchronousQueue:最多只能存储一个元素,每一个put操作必须等待一个take操作,否则不能继续添加元素
6)LinkedTransferQueue
LinkedTransferQueue是一个由链表结构组成的 无界阻塞TransferQueue队列 ,相对于其他阻塞队列LinkedTransferQueue多了tryTransfer和transfer方法。
7)LinkedBlockingDeque
LinkedBlockingDeque是一个由链表结构组成的双向阻塞队列。所谓双向队列指的你可以从队列的两端插入和移出元素。
双端队列因为多了一个操作队列的入口,在多线程同时入队时,也就减少了一半的竞争。
2.非阻塞队列
非阻塞队列也它的名字中不会包含 BlockingQueue 关键字,当队列满之后如果还有新元素入列会直接返回错误,并不会阻塞的等待着添加元素,如下图所示:
阻塞队列和非阻塞队列的区别:阻塞队列可以阻塞,非阻塞队列不能阻塞。
常见的非阻塞队列:
1)ConcurrentLinkedQueue
ConcurrentLinkedQueue:单向链表结构的无界并发队列, 非阻塞队列,由CAS实现线程安全,内部基于节点实现
2)ConcurrentLinkedDeque
ConcurrentLinkedDeque:双向链表结构的无界并发队列, 非阻塞队列,由CAS实现线程安全
3)PriorityQueue
PriorityQueue:内部基于数组实现,线程不安全的队列
3.双端队列
Deque表示双端队列,双端队列是在两端都可以进行插入和删除的队列。