队列(Queue)是一种常见的线程数据结构,它按照先进先出(FIFO)的原则管理元素。 根据队列的特性
- 添加元素时只能添加到队列尾部
- 删除数据时,只能删除头部
- 获取数据时只能取头部
队列
普通队列
除了基本的集合操作外,队列还提供插入,删除和检查操作。这些方法中的每一种都以两种形式存在:
- 条件不满足时(插入时队列空间不足,删除时队列数据为空)则会引发异常,
- 条件不满足时(插入时队列空间不足,删除时队列数据为空),将返回特殊值(取决于操作 null或false)。
插入操作的后一种形式专为与容量限制的队列实现而设计。在大多数实现中,插入操作不会失败。
| 抛异常 | 返回特殊值 | |
|---|---|---|
| 插入 | add(e) | offer(e) |
| 删除 | remove() | poll() |
| 取值 | element() | peek() |
java Queue 常见实现
-
java.util.PriorityQueue是 Java 中的一种优先级队列实现,它是基于堆数据结构实现的。优先级队列用于按照元素的优先级进行排序和获取,而不是按照插入顺序。元素在插入队列时会按照优先级顺序排列,允许高优先级元素优先被获取。 -
ConcurrentLinkedQueue是 Java 中的一种线程安全的队列实现,专门设计用于多线程并发环境下的操作,基于链表数据结构的无界队列。与传统的队列不同,ConcurrentLinkedQueue基于无锁算法实现,允许多个线程同时进行插入和移除操作,而不会引发竞态条件或死锁。
阻塞队列
BlockingQueue 它继承了Queue 插入,删除和取值操作除了普通队列的两种形式外,还有两种操作形式
- 条件不满足时(插入时队列空间不足,删除时队列数据为空),进行无限期阻塞
- 条件不满足时(插入时队列空间不足,删除时队列数据为空),阻塞一定的时长,返回特殊值(取决于操作 null或false)。
| 抛异常 | 返回特殊值 | 阻塞 | 超时 | |
|---|---|---|---|---|
| 插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
| 删除 | remove() | poll() | take() | poll(time, unit) |
| 取值 | element() | peek() | - | - |
java BlockingQueue 常见实现
- ArrayBlockingQueue:
java.util.concurrent.ArrayBlockingQueue是一个基于数组的阻塞队列实现。它具有固定的容量,需要在创建时指定容量大小。并且可以指定公平性与非公平性,默认情况下为非公平的,即不保证等待时间最长的队列最优先能够访问队列。当队列为空时,尝试从中获取元素的操作会被阻塞,直到有元素可用。当队列已满时,尝试插入元素的操作也会被阻塞,直到有足够的空间可用。 - LinkedBlockingQueue:
java.util.concurrent.LinkedBlockingQueue是一个基于链表的阻塞队列实现。它支持无界队列和有界队列,在创建 LinkedBlockingQueue 对象时如果不指定容量大小,则默认大小为 Integer.MAX_VALUE。当队列为空时,尝试从中获取元素的操作会被阻塞,直到有元素可用。当队列已满时,尝试插入元素的操作也会被阻塞,直到有足够的空间可用。 - PriorityBlockingQueue:
java.util.concurrent.PriorityBlockingQueue是一个无界的优先级队列,它支持根据元素的自然排序或指定的比较器进行排序。尝试获取元素的操作会阻塞,直到队列中有元素可用。 - DelayQueue:
java.util.concurrent.DelayQueue是一个基于PriorityQueue用于实现延迟任务调度的队列,DelayQueue中的元素实现了Delayed接口,只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue也是一个无界队列,因此往队列中插入数据的操作(生产者)永远不会被阻塞,而只有获取数据的操作(消费者)才会被阻塞。 - SynchronousQueue:
java.util.concurrent.SynchronousQueue是一个没有存储元素的阻塞队列,它用于在线程之间传递数据,一个线程尝试插入元素时会被阻塞,直到另一个线程尝试获取相同的元素。
双端队列
双端队列(Double-ended Queue),通常缩写为Deque,它继承了Queue 不仅支持队列(FIFO)操作,还支持栈(LIFO)操作,因此可以在队列的两端(前端和后端)进行插入和移除操作操作元素。
普通双端队列
以下是Java提供的实现Deque的常用类
- ArrayDeque:
ArrayDeque是一个基于数组实现的双端队列,容量是动态增长的,当需要时,它会自动扩展容量,因此不会出现队列满的情况。可以在队列的两端进行元素的插入和移除操作。 - LinkedList:
LinkedList也实现了Deque接口,并且是一个双向链表,因此可以在队列的两端进行元素的插入和移除操作,容量也是动态增长的。 - ConcurrentLinkedDeque 是 Java 并发包 (
java.util.concurrent) 中提供的一种线程安全的双端队列(Deque)实现,基于链表数据结构的无界队列。它允许在队列的两端(前端和后端)执行插入和移除操作,并且提供了线程安全的操作,适用于多线程并发环境
| 第一个元素(Head) | 最后一个元素(Tail) | |||
|---|---|---|---|---|
| 抛异常 | 特殊值 null或false | 抛异常 | 特殊值 null或false | |
| 插入 | addFirst(e) | offerFirst(e) | addLast(e) | offerLast(e) |
| 删除 | removeFirst() | pollFirst() | removeLast() | pollLast() |
| 取值 | getFirst() | peekFirst() | getLast() | peekLast() |
队列(Queue)和双端队列(Deque)方法的等价关系
Queue 方法 | 等价 Deque 方法 |
|---|---|
add(e) | addLast(e) |
offer(e) | offerLast(e) |
remove() | removeFirst() |
poll() | pollFirst() |
element() | getFirst() |
peek() | peekFirst() |
栈(Stack)和双端队列(Deque)方法的等价关系
Stack 方法 | 等价 Deque 方法 |
|---|---|
push(e) | addFirst(e) |
pop() | removeFirst() |
peek() | peekFirst() |
阻塞双端队列
阻塞双端队列是一种特殊类型的双端队列,它在队列为空或已满时可以阻塞等待操作
| 抛异常 | 特殊值 | 阻塞 | 超时 | |
|---|---|---|---|---|
| 第一个元素 (Head) | ||||
| 插入 | addFirst(e) | offerFirst(e) | putFirst(e) | offerFirst(e, time, unit) |
| 删除 | removeFirst() | pollFirst() | takeFirst() | pollFirst(time, unit) |
| 取值 | getFirst() | peekFirst() | - | - |
| 最后一个元素 (Tail) | ||||
| 插入 | addLast(e) | offerLast(e) | putLast(e) | offerLast(e, time, unit) |
| 删除 | removeLast() | pollLast() | takeLast() | pollLast(time, unit) |
| 取值 | getLast() | peekLast() | - | - |
阻塞双端队列的常见实现:
LinkedBlockingDeque: 是一个基于链表的阻塞双端队列。容量大小固定,一旦创建无法更改
阻塞队列(BlockingQueue)和阻塞双端队列(BlockingDeque)方法的等价关系
BlockingQueue 方法 | 等价于 BlockingDeque 方法 |
|---|---|
| 插入 | |
add(e) | addLast(e) |
offer(e) | offerLast(e) |
put(e) | putLast(e) |
offer(e, time, unit) | offerLast(e, time, unit) |
| 删除 | |
remove() | removeFirst() |
poll() | pollFirst() |
take() | takeFirst() |
poll(time, unit) | pollFirst(time, unit) |
| 取值 | |
element() | getFirst() |
peek() | peekFirst() |