Java 中的队列(Queue)是常用的数据结构,以下是详细的介绍和用法:

1. Queue 接口概述

Queue 接口是 Java Collections Framework 的一部分,继承自 Collection 接口,遵循先进先出(FIFO)原则。

2. 主要实现类

2.1 LinkedList

import java.util.LinkedList;
import java.util.Queue;

public class LinkedListQueueExample {
    public static void main(String[] args) {
        // 创建队列
        Queue<String> queue = new LinkedList<>();
        
        // 添加元素
        queue.add("A");  // 可能抛出异常
        queue.offer("B"); // 推荐使用,返回布尔值
        
        System.out.println("队列: " + queue); // [A, B]
        
        // 查看队首元素
        System.out.println("队首元素: " + queue.element()); // A
        System.out.println("队首元素: " + queue.peek());    // A
        
        // 移除元素
        String removed1 = queue.remove(); // 移除并返回A
        String removed2 = queue.poll();   // 移除并返回B
        
        System.out.println("移除的元素: " + removed1 + ", " + removed2);
        System.out.println("队列是否为空: " + queue.isEmpty()); // true
    }
}

2.2 PriorityQueue

import java.util.PriorityQueue;
import java.util.Queue;

public class PriorityQueueExample {
    public static void main(String[] args) {
        // 自然顺序(最小堆)
        Queue<Integer> minHeap = new PriorityQueue<>();
        minHeap.offer(5);
        minHeap.offer(1);
        minHeap.offer(3);
        
        System.out.println("优先级队列(最小堆):");
        while (!minHeap.isEmpty()) {
            System.out.println(minHeap.poll()); // 1, 3, 5
        }
        
        // 自定义比较器(最大堆)
        Queue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
        maxHeap.offer(5);
        maxHeap.offer(1);
        maxHeap.offer(3);
        
        System.out.println("优先级队列(最大堆):");
        while (!maxHeap.isEmpty()) {
            System.out.println(maxHeap.poll()); // 5, 3, 1
        }
    }
}

2.3 ArrayDeque(双端队列)

import java.util.ArrayDeque;
import java.util.Deque;

public class ArrayDequeExample {
    public static void main(String[] args) {
        // 作为队列使用(FIFO)
        Deque<String> queue = new ArrayDeque<>();
        queue.offerLast("A");
        queue.offerLast("B");
        queue.offerLast("C");
        
        System.out.println("队列操作:");
        while (!queue.isEmpty()) {
            System.out.println(queue.pollFirst()); // A, B, C
        }
        
        // 作为栈使用(LIFO)
        Deque<String> stack = new ArrayDeque<>();
        stack.offerFirst("A");
        stack.offerFirst("B");
        stack.offerFirst("C");
        
        System.out.println("栈操作:");
        while (!stack.isEmpty()) {
            System.out.println(stack.pollFirst()); // C, B, A
        }
    }
}

3. 阻塞队列(BlockingQueue)

3.1 ArrayBlockingQueue

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

public class ArrayBlockingQueueExample {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
        
        // 生产者线程
        Thread producer = new Thread(() -> {
            try {
                queue.put("任务1");
                queue.put("任务2");
                queue.put("任务3");
                System.out.println("生产者: 添加了3个任务");
                // queue.put("任务4"); // 会阻塞,直到有空间
                boolean success = queue.offer("任务4", 2, TimeUnit.SECONDS);
                System.out.println("添加任务4: " + success);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        // 消费者线程
        Thread consumer = new Thread(() -> {
            try {
                Thread.sleep(1000); // 等待生产者先添加任务
                for (int i = 0; i < 4; i++) {
                    String task = queue.take();
                    System.out.println("消费者: 处理 " + task);
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        producer.start();
        consumer.start();
        
        producer.join();
        consumer.join();
    }
}

3.2 LinkedBlockingQueue

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class LinkedBlockingQueueExample {
    public static void main(String[] args) {
        // 无界队列(理论上有界,最大为Integer.MAX_VALUE)
        BlockingQueue<Integer> unboundedQueue = new LinkedBlockingQueue<>();
        
        // 有界队列
        BlockingQueue<Integer> boundedQueue = new LinkedBlockingQueue<>(100);
        
        // 生产消费示例
        new Thread(() -> {
            try {
                for (int i = 1; i <= 5; i++) {
                    boundedQueue.put(i);
                    System.out.println("生产: " + i);
                    Thread.sleep(200);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
        
        new Thread(() -> {
            try {
                for (int i = 0; i < 5; i++) {
                    Integer item = boundedQueue.take();
                    System.out.println("消费: " + item);
                    Thread.sleep(300);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }
}

4. 并发队列

4.1 ConcurrentLinkedQueue

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ConcurrentLinkedQueueExample {
    public static void main(String[] args) {
        ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        // 多个生产者
        for (int i = 0; i < 2; i++) {
            final int producerId = i;
            executor.submit(() -> {
                for (int j = 0; j < 3; j++) {
                    String item = "生产者" + producerId + "-任务" + j;
                    queue.offer(item);
                    System.out.println("添加: " + item);
                }
            });
        }
        
        // 消费者
        executor.submit(() -> {
            while (true) {
                String item = queue.poll();
                if (item != null) {
                    System.out.println("处理: " + item);
                } else if (queue.isEmpty()) {
                    break;
                }
            }
        });
        
        executor.shutdown();
    }
}

5. 延迟队列(DelayQueue)

import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

class DelayedTask implements Delayed {
    private final String name;
    private final long startTime;
    
    public DelayedTask(String name, long delayMillis) {
        this.name = name;
        this.startTime = System.currentTimeMillis() + delayMillis;
    }
    
    @Override
    public long getDelay(TimeUnit unit) {
        long diff = startTime - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }
    
    @Override
    public int compareTo(Delayed other) {
        return Long.compare(this.startTime, ((DelayedTask) other).startTime);
    }
    
    @Override
    public String toString() {
        return "DelayedTask{" + "name='" + name + "'}";
    }
}

public class DelayQueueExample {
    public static void main(String[] args) throws InterruptedException {
        DelayQueue<DelayedTask> queue = new DelayQueue<>();
        
        // 添加延迟任务
        queue.put(new DelayedTask("任务1", 3000)); // 3秒后执行
        queue.put(new DelayedTask("任务2", 1000)); // 1秒后执行
        queue.put(new DelayedTask("任务3", 2000)); // 2秒后执行
        
        System.out.println("开始处理延迟任务...");
        
        while (!queue.isEmpty()) {
            DelayedTask task = queue.take();
            System.out.println("执行: " + task + " at " + System.currentTimeMillis());
        }
    }
}

6. 同步队列(SynchronousQueue)

import java.util.concurrent.SynchronousQueue;

public class SynchronousQueueExample {
    public static void main(String[] args) {
        SynchronousQueue<String> queue = new SynchronousQueue<>();
        
        // 生产者
        new Thread(() -> {
            try {
                String data = "重要数据";
                System.out.println("生产者: 准备发送 " + data);
                queue.put(data);
                System.out.println("生产者: 数据已发送");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
        
        // 消费者
        new Thread(() -> {
            try {
                Thread.sleep(1000); // 模拟处理时间
                String data = queue.take();
                System.out.println("消费者: 接收到 " + data);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }
}

7. 队列方法对比

方法 抛出异常 返回特殊值
插入 add(e) offer(e)
移除 remove() poll()
检查 element() peek()

阻塞队列特有方法:

  • put(e) - 阻塞直到空间可用
  • take() - 阻塞直到元素可用
  • offer(e, timeout, unit) - 带超时的插入
  • poll(timeout, unit) - 带超时的移除

8. 选择指南

  • 常规队列:LinkedList, ArrayDeque
  • 优先级处理:PriorityQueue
  • 生产消费模式:ArrayBlockingQueue, LinkedBlockingQueue
  • 高并发:ConcurrentLinkedQueue
  • 延迟任务:DelayQueue
  • 直接传递:SynchronousQueue

选择队列类型时需要考虑线程安全、性能需求、是否阻塞等因素。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐