Java中的队列
队列是Java集合框架中的一种重要数据结构,用于按照特定顺序存储和处理元素,通常遵循先进先出(FIFO)原则。Java提供了丰富的队列实现,适用于不同场景。
Queue接口
Queue是Java集合框架中的一个基础接口,继承自Collection接口,定义了队列的基本操作:
java
import java.util.Queue;
import java.util.LinkedList;
import java.util.ArrayDeque;
import java.util.PriorityQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.Comparator;
import java.util.Deque;
import java.util.concurrent.PriorityBlockingQueue;
public class JavaQueueExamples {
public static void main(String[] args) {
// 1. 基本队列操作示例
basicQueueOperations();
// 2. 常用队列实现示例
queueImplementations();
// 3. 阻塞队列示例
blockingQueueExample();
// 4. 延迟队列示例
delayQueueExample();
// 5. 双端队列示例
dequeExample();
// 6. 优先级队列示例
priorityQueueExample();
}
// 1. 基本队列操作
public static void basicQueueOperations() {
System.out.println("\n=== 基本队列操作 ===");
Queue<String> queue = new LinkedList<>();
// 添加元素
queue.add("第一个"); // 添加成功返回true,队列满则抛出异常
queue.offer("第二个"); // 添加成功返回true,队列满则返回false
// 查看队首元素但不移除
System.out.println("队首元素(peek): " + queue.peek()); // 队列为空返回null
System.out.println("队首元素(element): " + queue.element()); // 队列为空抛出异常
// 移除并返回队首元素
System.out.println("移除队首(poll): " + queue.poll()); // 队列为空返回null
System.out.println("移除队首(remove): " + queue.remove()); // 队列为空抛出异常
System.out.println("队列是否为空: " + queue.isEmpty());
}
// 2. 常用队列实现
public static void queueImplementations() {
System.out.println("\n=== 常用队列实现 ===");
// LinkedList实现的队列
Queue<String> linkedListQueue = new LinkedList<>();
linkedListQueue.offer("LinkedList队列元素1");
linkedListQueue.offer("LinkedList队列元素2");
System.out.println("LinkedList队列: " + linkedListQueue);
// ArrayDeque实现的队列 (更高效)
Queue<String> arrayDequeQueue = new ArrayDeque<>();
arrayDequeQueue.offer("ArrayDeque队列元素1");
arrayDequeQueue.offer("ArrayDeque队列元素2");
System.out.println("ArrayDeque队列: " + arrayDequeQueue);
}
// 3. 阻塞队列示例
public static void blockingQueueExample() {
System.out.println("\n=== 阻塞队列示例 ===");
// 有界阻塞队列
BlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(2);
try {
arrayBlockingQueue.put("任务1");
arrayBlockingQueue.put("任务2");
System.out.println("ArrayBlockingQueue: " + arrayBlockingQueue);
// 如果队列已满,put方法会阻塞
// arrayBlockingQueue.put("任务3"); // 会阻塞直到有空间
// 使用offer方法添加,可以设置超时时间
boolean added = arrayBlockingQueue.offer("任务3", 1, TimeUnit.SECONDS);
System.out.println("添加任务3是否成功: " + added);
// 取出元素
String task = arrayBlockingQueue.take(); // 如果队列为空,take方法会阻塞
System.out.println("取出任务: " + task);
// 使用poll方法取出,可以设置超时时间
String task2 = arrayBlockingQueue.poll(1, TimeUnit.SECONDS);
System.out.println("取出任务2: " + task2);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 无界阻塞队列
BlockingQueue<String> linkedBlockingQueue = new LinkedBlockingQueue<>();
linkedBlockingQueue.offer("LinkedBlockingQueue元素");
System.out.println("LinkedBlockingQueue: " + linkedBlockingQueue);
}
// 4. 延迟队列示例
public static void delayQueueExample() {
System.out.println("\n=== 延迟队列示例 ===");
DelayQueue<DelayedElement> delayQueue = new DelayQueue<>();
// 添加延迟元素,分别延迟1秒、2秒、3秒
delayQueue.offer(new DelayedElement("任务1", 1000));
delayQueue.offer(new DelayedElement("任务2", 2000));
delayQueue.offer(new DelayedElement("任务3", 3000));
System.out.println("延迟队列大小: " + delayQueue.size());
try {
// 尝试获取,但只有延迟到期的元素才能被取出
System.out.println("开始获取延迟队列元素...");
// 获取并移除第一个可用的元素
DelayedElement element1 = delayQueue.take();
System.out.println("取出元素: " + element1.getName() + ", 时间: " + System.currentTimeMillis());
// 获取并移除第二个可用的元素
DelayedElement element2 = delayQueue.take();
System.out.println("取出元素: " + element2.getName() + ", 时间: " + System.currentTimeMillis());
// 使用poll带超时的方法获取第三个元素
DelayedElement element3 = delayQueue.poll(5, TimeUnit.SECONDS);
if (element3 != null) {
System.out.println("取出元素: " + element3.getName() + ", 时间: " + System.currentTimeMillis());
} else {
System.out.println("超时未获取到元素");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 5. 双端队列示例
public static void dequeExample() {
System.out.println("\n=== 双端队列示例 ===");
Deque<String> deque = new ArrayDeque<>();
// 在队首和队尾添加元素
deque.offerFirst("队首元素1");
deque.offerLast("队尾元素1");
deque.offerFirst("队首元素2");
deque.offerLast("队尾元素2");
System.out.println("双端队列: " + deque); // [队首元素2, 队首元素1, 队尾元素1, 队尾元素2]
// 查看队首和队尾元素
System.out.println("队首元素: " + deque.peekFirst());
System.out.println("队尾元素: " + deque.peekLast());
// 移除队首和队尾元素
System.out.println("移除队首: " + deque.pollFirst());
System.out.println("移除队尾: " + deque.pollLast());
System.out.println("处理后的双端队列: " + deque);
// 使用栈方法 (LIFO)
deque.push("栈顶元素"); // 等同于addFirst()
System.out.println("添加栈顶元素后: " + deque);
System.out.println("弹出栈顶: " + deque.pop()); // 等同于removeFirst()
System.out.println("弹出后的队列: " + deque);
}
// 6. 优先级队列示例
public static void priorityQueueExample() {
System.out.println("\n=== 优先级队列示例 ===");
// 自然排序的优先级队列 (小顶堆)
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
minHeap.offer(10);
minHeap.offer(5);
minHeap.offer(15);
minHeap.offer(1);
System.out.print("自然排序优先级队列出队顺序: ");
while (!minHeap.isEmpty()) {
System.out.print(minHeap.poll() + " ");
}
System.out.println();
// 自定义比较器的优先级队列 (大顶堆)
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
maxHeap.offer(10);
maxHeap.offer(5);
maxHeap.offer(15);
maxHeap.offer(1);
System.out.print("自定义排序优先级队列出队顺序: ");
while (!maxHeap.isEmpty()) {
System.out.print(maxHeap.poll() + " ");
}
System.out.println();
// 使用对象和自定义比较器
PriorityQueue<Task> taskQueue = new PriorityQueue<>((t1, t2) -> t1.getPriority() - t2.getPriority());
taskQueue.offer(new Task("普通任务", 3));
taskQueue.offer(new Task("紧急任务", 1));
taskQueue.offer(new Task("低优先级任务", 5));
taskQueue.offer(new Task("高优先级任务", 2));
System.out.println("任务优先级队列出队顺序: ");
while (!taskQueue.isEmpty()) {
System.out.println(taskQueue.poll());
}
// 线程安全的优先级阻塞队列
PriorityBlockingQueue<Integer> priorityBlockingQueue = new PriorityBlockingQueue<>();
priorityBlockingQueue.offer(10);
priorityBlockingQueue.offer(5);
priorityBlockingQueue.offer(15);
System.out.println("PriorityBlockingQueue: " + priorityBlockingQueue);
}
}
// 延迟队列元素类
java
class DelayedElement implements Delayed {
private String name;
private long expireTime; // 过期时间,单位毫秒
public DelayedElement(String name, long delayInMillis) {
this.name = name;
this.expireTime = System.currentTimeMillis() + delayInMillis;
}
public String getName() {
return name;
}
@Override
public long getDelay(TimeUnit unit) {
// 计算剩余延迟时间
long diff = expireTime - System.currentTimeMillis();
return unit.convert(diff, TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed other) {
// 比较延迟时间
if (other == this) {
return 0;
}
if (other instanceof DelayedElement) {
DelayedElement otherElement = (DelayedElement) other;
return Long.compare(expireTime, otherElement.expireTime);
}
long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS);
return (diff == 0) ? 0 : ((diff < 0) ? -1 : 1);
}
@Override
public String toString() {
return "DelayedElement{name='" + name + "', expireTime=" + expireTime + "}";
}
}
// 任务类(用于优先级队列示例)
java
class Task {
private String name;
private int priority; // 优先级,数字越小优先级越高
public Task(String name, int priority) {
this.name = name;
this.priority = priority;
}
public String getName() {
return name;
}
public int getPriority() {
return priority;
}
@Override
public String toString() {
return "Task{name='" + name + "', priority=" + priority + "}";
}
}
Queue接口的核心方法
Queue接口定义了两组核心操作方法,它们在不同情况下的行为略有不同:
操作抛出异常返回特殊值
java
添加元素add(e)offer(e)
移除元素remove()poll()
检查元素element()peek()
常见的队列实现
Java提供了多种队列实现,适合不同的应用场景:
-
非阻塞队列
LinkedList: 基于链表的队列实现,适合频繁添加/删除操作
ArrayDeque: 基于数组的双端队列,通常比LinkedList性能更好
PriorityQueue: 优先级队列,基于堆实现,元素按优先级出队
-
阻塞队列 (BlockingQueue)
阻塞队列支持在队列为空/满时阻塞操作,非常适合生产者-消费者模式:
ArrayBlockingQueue: 有界阻塞队列,基于数组实现
LinkedBlockingQueue: 可选有界阻塞队列,基于链表实现
PriorityBlockingQueue: 无界优先级阻塞队列
DelayQueue: 延迟队列,元素只有到达指定延迟时间才能被取出
SynchronousQueue: 没有容量的阻塞队列,每个插入操作必须等待相应的移除操作
- 双端队列 (Deque)
双端队列允许在两端进行插入和移除操作:
ArrayDeque: 基于数组的可调整大小的双端队列
LinkedList: 也实现了Deque接口
LinkedBlockingDeque: 线程安全的双端阻塞队列
队列的应用场景
任务调度:使用DelayQueue或PriorityQueue实现定时任务
线程池:阻塞队列用于存储等待执行的任务
消息队列:作为生产者-消费者之间的缓冲区
资源池:管理共享资源的分配和释放
缓存:实现LRU缓存等缓存策略
广度优先搜索:在图算法中使用队列进行BFS遍历