在 Java 中,队列(Queue)是一个常用的数据结构,用于按特定顺序(通常是先入先出,FIFO)处理元素。Java 提供了多个实现,可以适用于不同的场景和需求。以下是 Java 常用的队列及其使用场景和用法:
1. LinkedList
使用场景:
- 双端队列(Deque) :可以作为队列(FIFO)或栈(LIFO)使用。
- 通用队列:适用于需要基本队列功能的小型场景。
用法:
Queue<Integer> queue = new LinkedList<>();
queue.offer(1); // 添加元素
queue.offer(2);
System.out.println(queue.poll()); // 移除并返回队首元素,输出1
System.out.println(queue.peek()); // 查看队首元素,不移除,输出2
2. PriorityQueue
使用场景:
- 优先级队列:按元素的自然顺序(或提供的比较器顺序)排序。
- 任务调度:处理需要优先级的任务,例如任务队列或事件管理。
用法:
Queue<Integer> priorityQueue = new PriorityQueue<>();
priorityQueue.offer(3);
priorityQueue.offer(1);
priorityQueue.offer(2);
System.out.println(priorityQueue.poll()); // 输出1(按升序)
3. ArrayDeque
使用场景:
- 高效的双端队列:比
LinkedList更高效,适用于栈或队列的实现。 - 替代栈:比
Stack类更推荐使用。
用法:
Deque<Integer> deque = new ArrayDeque<>();
deque.offerFirst(1); // 从队首添加元素
deque.offerLast(2); // 从队尾添加元素
System.out.println(deque.pollFirst()); // 从队首移除并返回,输出1
System.out.println(deque.pollLast()); // 从队尾移除并返回,输出2
4. ConcurrentLinkedQueue
使用场景:
- 线程安全队列:适用于多线程环境下的非阻塞队列。
- 高效的并发操作:适合生产者-消费者模型。
用法:
Queue<Integer> concurrentQueue = new ConcurrentLinkedQueue<>();
concurrentQueue.offer(1);
concurrentQueue.offer(2);
System.out.println(concurrentQueue.poll()); // 输出1
System.out.println(concurrentQueue.peek()); // 输出2
5. LinkedBlockingQueue
使用场景:
- 阻塞队列:适用于生产者-消费者模式,具有容量限制。
- 线程安全:在高并发场景下使用。
用法:
BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<>(2);
blockingQueue.put(1); // 添加元素,如果队列满则阻塞
blockingQueue.put(2);
// blockingQueue.put(3); // 阻塞直到有空间
System.out.println(blockingQueue.take()); // 移除并返回队首元素,输出1
6. ArrayBlockingQueue
使用场景:
- 固定大小的阻塞队列:比
LinkedBlockingQueue更高效,适合固定容量的场景。 - 线程安全:用于线程间通信。
用法:
BlockingQueue<Integer> arrayBlockingQueue = new ArrayBlockingQueue<>(2);
arrayBlockingQueue.put(1);
arrayBlockingQueue.put(2);
// arrayBlockingQueue.put(3); // 阻塞直到有空间
System.out.println(arrayBlockingQueue.take()); // 输出1
7. PriorityBlockingQueue
使用场景:
- 线程安全的优先级队列:用于需要优先级的多线程场景。
- 无界队列:默认容量无限。
用法:
BlockingQueue<Integer> priorityBlockingQueue = new PriorityBlockingQueue<>();
priorityBlockingQueue.put(3);
priorityBlockingQueue.put(1);
priorityBlockingQueue.put(2);
System.out.println(priorityBlockingQueue.take()); // 输出1(按优先级)
8. DelayQueue
使用场景:
- 延迟队列:用于定时任务调度,只有延迟时间到期后元素才会出队。
- 任务延迟处理:适合处理带有延迟的任务。
用法:
import java.util.concurrent.*;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
class DelayedTask implements Delayed {
private long delayTime;
private long expireTime;
public DelayedTask(long delayTime) {
this.delayTime = delayTime;
this.expireTime = System.currentTimeMillis() + delayTime;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
}
@Override
public String toString() {
return "Task with delay: " + delayTime;
}
}
DelayQueue<DelayedTask> delayQueue = new DelayQueue<>();
delayQueue.put(new DelayedTask(3000)); // 延迟3秒
System.out.println("Task added...");
System.out.println(delayQueue.take()); // 等待3秒后输出
9. SynchronousQueue
使用场景:
- 无缓冲队列:用于直接传递元素,生产者和消费者必须相互等待。
- 生产者-消费者模型:需要即时传递的场景。
用法:
BlockingQueue<Integer> synchronousQueue = new SynchronousQueue<>();
new Thread(() -> {
try {
synchronousQueue.put(1); // 阻塞等待消费者
System.out.println("Produced 1");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
new Thread(() -> {
try {
System.out.println("Consumed " + synchronousQueue.take()); // 输出1
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
总结
| 队列类型 | 特点 | 使用场景 |
|---|---|---|
| LinkedList | FIFO/双端队列 | 通用队列、小型场景 |
| PriorityQueue | 优先级排序 | 任务调度 |
| ArrayDeque | 高效双端队列 | 栈或队列实现 |
| ConcurrentLinkedQueue | 非阻塞线程安全队列 | 高并发的无界队列 |
| LinkedBlockingQueue | 有界阻塞队列 | 高并发的生产者-消费者模型 |
| ArrayBlockingQueue | 固定大小的阻塞队列 | 高并发的生产者-消费者模型 |
| PriorityBlockingQueue | 线程安全优先级队列 | 带优先级的任务调度 |
| DelayQueue | 带延迟的队列 | 定时任务 |
| SynchronousQueue | 无缓冲队列 | 实时任务传递 |
根据需求选择合适的队列可以大大提高代码的效率和可读性。