数据结构 - Java 队列

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提供了多种队列实现,适合不同的应用场景:

  1. 非阻塞队列

    LinkedList: 基于链表的队列实现,适合频繁添加/删除操作

    ArrayDeque: 基于数组的双端队列,通常比LinkedList性能更好

    PriorityQueue: 优先级队列,基于堆实现,元素按优先级出队

  2. 阻塞队列 (BlockingQueue)

    阻塞队列支持在队列为空/满时阻塞操作,非常适合生产者-消费者模式:

ArrayBlockingQueue: 有界阻塞队列,基于数组实现

LinkedBlockingQueue: 可选有界阻塞队列,基于链表实现

PriorityBlockingQueue: 无界优先级阻塞队列

DelayQueue: 延迟队列,元素只有到达指定延迟时间才能被取出

SynchronousQueue: 没有容量的阻塞队列,每个插入操作必须等待相应的移除操作

  1. 双端队列 (Deque)
    双端队列允许在两端进行插入和移除操作:

ArrayDeque: 基于数组的可调整大小的双端队列

LinkedList: 也实现了Deque接口

LinkedBlockingDeque: 线程安全的双端阻塞队列

队列的应用场景

任务调度:使用DelayQueue或PriorityQueue实现定时任务

线程池:阻塞队列用于存储等待执行的任务

消息队列:作为生产者-消费者之间的缓冲区

资源池:管理共享资源的分配和释放

缓存:实现LRU缓存等缓存策略

广度优先搜索:在图算法中使用队列进行BFS遍历

相关推荐
九月十九1 小时前
java使用aspose读取word里的图片
java·word
一 乐2 小时前
民宿|基于java的民宿推荐系统(源码+数据库+文档)
java·前端·数据库·vue.js·论文·源码
爱记录的小磊2 小时前
java-selenium自动化快速入门
java·selenium·自动化
鹏码纵横2 小时前
已解决:java.lang.ClassNotFoundException: com.mysql.jdbc.Driver 异常的正确解决方法,亲测有效!!!
java·python·mysql
weixin_985432112 小时前
Spring Boot 中的 @ConditionalOnBean 注解详解
java·spring boot·后端
Mr Aokey2 小时前
Java UDP套接字编程:高效实时通信的实战应用与核心类解析
java·java-ee
冬天vs不冷2 小时前
Java分层开发必知:PO、BO、DTO、VO、POJO概念详解
java·开发语言
hong_zc3 小时前
Java 文件操作与IO流
java·文件操作·io 流
木棉软糖3 小时前
【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space
java·maven·intellij-idea