超全面Java中的队列(Queue)

简介: Java中的`Queue`接口位于`java.util`包,继承自`Collection`,用于存储待处理的元素,通常遵循FIFO原则。它包含`add`、`offer`、`poll`等方法,支持多种实现类,如`LinkedList`、`PriorityQueue`、`ArrayDeque`、`ConcurrentLinkedQueue`及`BlockingQueue`系列。

在Java中,Queue接口是java.util包的一部分,继承自Collection接口,用于在处理前保存元素。它遵循FIFO(先进先出)原则,但优先级队列和LIFO队列除外。以下是关于Java队列的超全面介绍:

1. Queue接口的基本方法

方法 描述 异常情况(失败时) 返回特殊值(失败时)
add(e) 添加元素到队列尾部 IllegalStateException false
offer(e) 尝试添加元素(更适合有容量限制的队列) - false
remove() 移除并返回队首元素 NoSuchElementException -
poll() 移除并返回队首元素(队列为空时返回null - null
element() 返回队首元素(不移除) NoSuchElementException -
peek() 返回队首元素(不移除,队列为空时返回null - null

2. 常用实现类

2.1 LinkedList

  • 特点:实现了QueueDeque接口,支持双向队列操作。
  • 适用场景:频繁插入/删除元素的场景。
Queue<String> queue = new LinkedList<>();
queue.offer("A");
queue.offer("B");
System.out.println(queue.poll()); // 输出: A

2.2 PriorityQueue

  • 特点:基于优先级堆实现,元素按自然顺序或指定比较器排序。
  • 注意:不允许null元素,非线程安全。
Queue<Integer> priorityQueue = new PriorityQueue<>();
priorityQueue.offer(3);
priorityQueue.offer(1);
System.out.println(priorityQueue.poll()); // 输出: 1(最小元素优先)

2.3 ArrayDeque

  • 特点:动态数组实现的双端队列,不允许null元素。
  • 优势:无容量限制,比LinkedList在队列操作上更高效。
Deque<String> deque = new ArrayDeque<>();
deque.offerFirst("A");
deque.offerLast("B");
System.out.println(deque.pollLast()); // 输出: B

2.4 ConcurrentLinkedQueue

  • 特点:基于链表的无界线程安全队列,采用CAS(Compare-and-Swap)操作。
  • 适用场景:高并发环境。
Queue<String> concurrentQueue = new ConcurrentLinkedQueue<>();
concurrentQueue.offer("Task1");
concurrentQueue.poll(); // 线程安全操作

2.5 BlockingQueue接口及实现类

用于线程间通信,支持阻塞操作(如put()take())。

  • ArrayBlockingQueue:有界数组实现的阻塞队列。
  • LinkedBlockingQueue:可选有界的链表阻塞队列。
  • PriorityBlockingQueue:支持优先级的无界阻塞队列。
  • DelayQueue:延迟元素的无界阻塞队列,元素必须实现Delayed接口。
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(10);
blockingQueue.put("Item"); // 队列满时阻塞
String item = blockingQueue.take(); // 队列空时阻塞

3. 双端队列(Deque)

Deque接口继承自Queue,支持两端元素插入和删除。

  • 常用方法
    • addFirst(e)/offerFirst(e)
    • addLast(e)/offerLast(e)
    • removeFirst()/pollFirst()
    • removeLast()/pollLast()
    • getFirst()/peekFirst()
    • getLast()/peekLast()
Deque<Integer> deque = new ArrayDeque<>();
deque.push(1); // 等价于 addFirst()
deque.push(2);
System.out.println(deque.pop()); // 输出: 2(LIFO栈操作)

4. 队列与线程安全

  • 非线程安全队列LinkedListPriorityQueueArrayDeque
  • 线程安全队列
    • ConcurrentLinkedQueue:非阻塞线程安全队列。
    • BlockingQueue及其实现类:阻塞线程安全队列。

示例:生产者-消费者模式

BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();

// 生产者线程
new Thread(() -> {
   
    try {
   
        queue.put(1);
    } catch (InterruptedException e) {
   
        Thread.currentThread().interrupt();
    }
}).start();

// 消费者线程
new Thread(() -> {
   
    try {
   
        Integer item = queue.take();
    } catch (InterruptedException e) {
   
        Thread.currentThread().interrupt();
    }
}).start();

5. 队列的应用场景

  • 消息队列:实现异步处理(如RabbitMQ、Kafka)。
  • 任务调度:按顺序执行任务。
  • 广度优先搜索(BFS):使用队列存储待处理节点。
  • 缓存淘汰策略:FIFO缓存(如LinkedHashMapremoveEldestEntry方法)。

6. 注意事项

  • 避免null元素:多数队列实现不允许nullPriorityQueueConcurrentLinkedQueue会直接抛出异常。
  • 容量限制:有界队列(如ArrayBlockingQueue)需处理满队列情况,避免阻塞或拒绝操作。
  • 迭代器:队列的迭代器可能是弱一致性的,尤其是并发队列。

总结

队列类型 有序性 线程安全 有界性 适用场景
LinkedList FIFO 无界 灵活的双向队列操作
PriorityQueue 优先级 无界 按优先级处理元素
ArrayDeque FIFO/LIFO 动态扩容 高效的双端操作
ConcurrentLinkedQueue FIFO 无界 高并发场景
ArrayBlockingQueue FIFO 有界 固定容量的线程安全队列
DelayQueue 延迟时间 无界 延迟任务调度

根据具体需求选择合适的队列实现,兼顾性能与线程安全。

目录
相关文章
|
Java Linux 程序员
Linux 下 JNA 调用动态连接库文件 so
Linux 下 JNA 调用动态连接库文件 so
938 0
|
Java Spring
【注解】Spring AOP 面向切面编程之@Around的详细用法
【注解】Spring AOP 面向切面编程之@Around的详细用法
3968 0
|
缓存
idea更改默认缓存位置步骤
在idea使用中,会产生大量的缓存,一般默认存放在C盘里面,会加大C盘的储存负担,如果C盘足够大,可以不考虑更改idea的缓存位置
4912 0
idea更改默认缓存位置步骤
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
Java 开发者 Spring
【SpringBoot 异步魔法】@Async 注解:揭秘 SpringBoot 中异步方法的终极奥秘!
【8月更文挑战第25天】异步编程对于提升软件应用的性能至关重要,尤其是在高并发环境下。Spring Boot 通过 `@Async` 注解简化了异步方法的实现。本文详细介绍了 `@Async` 的基本用法及配置步骤,并提供了示例代码展示如何在 Spring Boot 项目中创建与管理异步任务,包括自定义线程池、使用 `CompletableFuture` 处理结果及异常情况,帮助开发者更好地理解和运用这一关键特性。
2810 1
|
11月前
|
存储 JavaScript 前端开发
务必把握Map对象在JavaScript循环中的使用细节
由于Map对象跟传统的对象类似,但提供了更多的迭代功能,它被广泛用来代替Object存储键值对。适当的使用Map和配套的迭代方法,可以让代码更加清晰,提高数据操作的灵活性和效率。在数据量大或者对迭代顺序有特定需求时,Map会是一个很好的选择。
603 0
|
搜索推荐 算法 Java
2025 年互联网大厂校园招聘 JAVA 工程师笔试题及备考要点解析
本文针对互联网大厂校招Java工程师笔试题进行解析,涵盖基础知识、面向对象编程、数据结构与算法、异常处理及集合框架等核心内容。从数据类型、运算符到流程控制语句,从类与对象、继承多态到数组链表、排序算法,再到异常捕获与集合框架应用,结合实际案例深入剖析,助你系统掌握考点,提升应试能力。资源链接:[点此获取](https://pan.quark.cn/s/14fcf913bae6)。
410 9
|
NoSQL Java Redis
springboot怎么使用Redisson
通过以上步骤,已经详细介绍了如何在Spring Boot项目中使用Redisson,包括添加依赖、配置Redisson、创建配置类以及使用Redisson实现分布式锁和分布式集合。Redisson提供了丰富的分布式数据结构和工具,可以帮助开发者更高效地实现分布式系统。通过合理使用这些工具,可以显著提高系统的性能和可靠性。
4284 34
|
消息中间件 存储 前端开发
Java队列(Queue)详解与应用
Java队列(Queue)详解与应用
603 1
|
存储 监控 Java
JAVA线程池有哪些队列? 以及它们的适用场景案例
不同的线程池队列有着各自的特点和适用场景,在实际使用线程池时,需要根据具体的业务需求、系统资源状况以及对任务执行顺序、响应时间等方面的要求,合理选择相应的队列来构建线程池,以实现高效的任务处理。
980 12