前端视角 Java Web 入门手册 2.4.3:集合框架——Queue

Java 中的 Queue 接口是集合框架中用于表示队列的核心接口,遵循先进先出(FIFO)原则,但也支持优先级队列 PriorityQueue 或双端队列 Deque

方法签名 描述
boolean add(E e) 将指定元素添加到队列的尾部。若队列无法添加元素,则抛出异常
boolean offer(E e) 将指定元素添加到队列的尾部。若队列无法添加元素,则返回 false
E remove() 移除并返回队列头部的元素。若队列为空,则抛出异常
E poll() 移除并返回队列头部的元素。若队列为空,则返回 null
E element() 返回队列头部的元素,但不移除它。若队列为空,则抛出异常
E peek() 返回队列头部的元素,但不移除它。若队列为空,则返回 null
int size() 返回队列中的元素数量
boolean isEmpty() 判断队列是否为空

Java 队列有多种实现,最常使用的有三种类型

  • 普通队列:实现 Queue 接口,先进先出(FIFO)队列
  • 双端队列:实现 Deque 接口,在队首或者队尾都可以进行元素的插入和删除操作的队列
  • 优先队列:元素按照优先级排序,对队列中删除元素时自动将优先级最高的元素出队

双端队列

双端队列头尾都可以插入、删除,使用其中的部分方法可以实现 FIFO 普通队列、LIFO 堆栈,所有双端队列都实现 Deque(Double End Queue 接口)

java 复制代码
public interface Deque<E> extends Queue<E> {

    // 向队首添加一个元素;如果有空间则添加成功返回true,否则则抛出异常
    void addFirst(E e);
    // 向队尾添加一个元素;如果有空间则添加成功返回true,否则则抛出异常
    void addLast(E e);
	
    // 向队首添加一个元素;如果有空间则添加成功返回true,否则返回false
    boolean offerFirst(E e);
    // 向队尾添加一个元素;如果有空间则添加成功返回true,否则返回false
    boolean offerLast(E e);
  
    // 从队首删除一个元素;如果元素存在则返回队首元素,否则抛出异常
    E removeFirst();
    // 从队尾删除一个元素;如果元素存在则返回队尾元素,否则抛出异常
    E removeLast();
		
    // 从队首删除一个元素;如果元素存在则返回队首元素,否则返回null
    E pollFirst();
    // 从队尾删除一个元素;如果元素存在则返回队首元素,否则返回null
    E pollLast();
  
    // 从队首获取一个元素,但是不删除;如果元素存在则返回队首元素,否则抛出异常
    E getFirst();
    // 从队尾获取一个元素,但是不删除;如果元素存在则返回队尾元素,否则抛出异常
    E getLast();

    // 从队首获取一个元素,但是不删除;如果元素存在则返回队首元素,否则返回null
    E peekFirst();
    // 从队尾获取一个元素,但是不删除;如果元素存在则返回队尾元素,否则返回null
    E peekLast();

    // ...
}

LinkedList

在 List 章节出现的 LinkedList 还实现了 Queue、Deque 接口,同时是一个双端队列

java 复制代码
public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
        
}

使用 LinkedList 可以模拟 LIFO 堆栈

java 复制代码
import java.util.LinkedList;

public class Stack<E> {
  private LinkedList<E> list;

  public Stack() {
    list = new LinkedList<E>();
  }

  public void push(E value) {
    list.addFirst(value);
  }

  public E pop() {
    return list.removeFirst();
  }

  public E peek() {
    return list.getFirst();
  }

  public boolean isEmpty() {
    return list.isEmpty();
  }

  public int size() {
    return list.size();
  }
}

ArrayDeque

ArrayDeque 是 Deque 接口的数组实现双端队列,也实现了 Queue 接口。ArrayDeque 基于数组实现,提供了比 LinkedList 更高效的队列和栈操作

java 复制代码
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Queue;

public class ArrayDequeExample {
    public static void main(String[] args) {
        // 作为 Queue 使用
        Queue<String> queue = new ArrayDeque<>();
        queue.offer("Apple");
        queue.offer("Banana");
        queue.add("Cherry");

        System.out.println("初始队列: " + queue); // 输出: 初始队列: [Apple, Banana, Cherry]

        // 移除元素
        System.out.println("移除的元素: " + queue.poll()); // 输出: 移除的元素: Apple
        System.out.println("移除后队列: " + queue);        // 输出: 移除后队列: [Banana, Cherry]

        // 作为 Deque 使用
        Deque<Integer> deque = new ArrayDeque<>();
        deque.push(100);
        deque.push(200);
        deque.addLast(300);

        System.out.println("Deque: " + deque); // 输出: Deque: [200, 100, 300]

        // 弹出元素
        System.out.println("弹出的元素: " + deque.pop()); // 输出: 弹出的元素: 200
        System.out.println("弹出后 Deque: " + deque);     // 输出: 弹出后 Deque: [100, 300]
    }
}

优先级队列:PriorityQueue

优先队列基于堆实现,元素按照优先级排序,插入元素时根据指定的优先级比较方法(默认是自然顺序),确定元素优先级后插入到队列合适位置,对队列中删除元素时自动将优先级最高的元素出队

java 复制代码
import java.util.Comparator;
import java.util.PriorityQueue;

public class QueueDemo {
  public static void main(String[] args) {
    PriorityQueue<Integer> pq = new PriorityQueue<>(new MyComparator());
    pq.add(1);
    pq.add(2);
    pq.add(3);
    pq.add(4);
    pq.add(5);
    pq.add(6);

    while (!pq.isEmpty()) {
      System.out.print(pq.poll() + " "); // 2 4 6 1 3 5
    }
  }
}

// 偶数优先,升序
class MyComparator implements Comparator<Integer> {
  @Override
  public int compare(Integer x, Integer y) {
    if (x % 2 == 0 && y % 2 == 0) {
      return x - y;
    } else if (x % 2 == 0) {
      return -1;
    } else if (y % 2 == 0) {
      return 1;
    } else {
      return x - y;
    }
  }
}

线程安全

前面提到的几种 Queue 的实现是非线程安全的,如果在多个线程进行入队和出队操作,将会产生数据不一致的情况。Java 提供了两种线程安全队列的实现方式

  • 阻塞机制:通过使用锁的方式来实现,在入队和出队时通过加锁避免并发操作,常见的有

    • ArrayBlockingQueue
    • LinedBlockingQueue
    • PriorityBlockingQueue
    • SynchronousQueue
    • DelayQueue
  • 非阻塞机制:使用非阻塞算法 CAS(Compare and Swap)方式实现,无锁设计,高并发场景性能优异,典型实现是 ConcurrentLinkedQueue

java 复制代码
ConcurrentLinkedQueue<String> concurrentQueue = new ConcurrentLinkedQueue<>();

// 添加元素
concurrentQueue.add("Apple");
concurrentQueue.offer("Banana");
concurrentQueue.add("Cherry");

System.out.println("初始 ConcurrentLinkedQueue: " + concurrentQueue);
// 输出: 初始 ConcurrentLinkedQueue: [Apple, Banana, Cherry]

// 移除元素
System.out.println("移除的元素: " + concurrentQueue.poll()); // 输出: 移除的元素: Apple
System.out.println("移除后 ConcurrentLinkedQueue: " + concurrentQueue);
// 输出: 移除后 ConcurrentLinkedQueue: [Banana, Cherry]

// 查看头部元素
System.out.println("ConcurrentLinkedQueue 头部元素: " + concurrentQueue.peek()); // 输出: Banana

Queue 的选择

场景 推荐实现类 理由
单线程简单队列 LinkedList / ArrayDeque 轻量高效
按优先级处理元素 PriorityQueue 基于堆的优先级排序
高并发非阻塞队列 ConcurrentLinkedQueue 无锁线程安全,性能高
生产者-消费者模型(阻塞) ArrayBlockingQueue 固定容量,支持公平锁
无界生产者-消费者模型 LinkedBlockingQueue 默认无界,吞吐量高
需要双端队列操作 ArrayDeque 循环数组实现,性能优于 LinkedList
相关推荐
二十雨辰13 分钟前
[Java]函数式编程
java·开发语言
西岭千秋雪_23 分钟前
ReentrantReadWriteLock源码分析
java·开发语言·jvm
JavaGuide1 小时前
IDEA 接入 DeepSeek,太酷了!
java·idea·aio·deepseek
计算机-秋大田1 小时前
基于微信小程序的绘画学习平台的设计与开发
spring boot·后端·学习·微信小程序·小程序·课程设计
呦呦鹿鸣Rzh1 小时前
HTML-表格,表单标签
java·前端·html
努力的小雨1 小时前
腾讯云HAI与DeepSeek携手打造私有化高效代码助手
后端
neeef_se2 小时前
Java实习生面试题汇总
java·开发语言
孔瑾熙2 小时前
Ruby语言的循环实现
开发语言·后端·golang
LUCIAZZZ2 小时前
Hot100之图论
java·数据结构·算法·leetcode·深度优先·图论
我码玄黄3 小时前
高效 MyBatis SQL 写法一
后端·sql·tomcat·mybatis