【Java第57集】java Queue详解

1. Queue接口概述

1.1 核心概念

  • Queue 是 Java 集合框架中的核心接口之一,继承自 Collection 接口。
  • 核心特性
    • 先进先出(FIFO):默认遵循 FIFO 原则(某些实现如 PriorityQueue 例外)。
    • 有序性:元素按插入顺序排列(PriorityQueue 按优先级排序)。
    • 无索引:无法通过索引直接访问元素。
    • 允许 null:部分实现类支持存储 null 元素(PriorityQueue 不允许)。

1.2 Queue与Collection的区别

特性QueueCollection
数据结构无索引、FIFO(或优先级)无索引、可重复(List)或唯一(Set)
存取方式支持队列操作(入队、出队)支持迭代器或 toArray() 访问
唯一性不强制唯一性(PriorityQueue 可重复)Set 不允许重复,List 允许重复
实现类LinkedListPriorityQueueArrayDequeList(如 ArrayList)、Set(如 HashSet

2. Queue的核心方法

2.1 插入元素

  • boolean add(E e)
    添加元素,成功返回 true,若队列已满(有界队列)抛出 IllegalStateException
  • boolean offer(E e)
    添加元素,成功返回 true,若队列已满返回 false(不抛异常)。

2.2 移除元素

  • E remove()
    移除并返回队首元素,若队列为空抛出 NoSuchElementException
  • E poll()
    移除并返回队首元素,若队列为空返回 null

2.3 查看队首元素

  • E element()
    返回队首元素但不移除,若队列为空抛出 NoSuchElementException
  • E peek()
    返回队首元素但不移除,若队列为空返回 null

3. Queue的常见实现类

3.1 LinkedList

  • 底层结构:双向链表。

  • 特点

    • 非线程安全:需外部同步(如 Collections.synchronizedQueue)。
    • 动态大小:支持 addFirstaddLast(作为 Deque 使用)。
    • 适用场景:简单队列或双端队列(Deque)。
  • 示例代码:

    import java.util.LinkedList;
    import java.util.Queue;
    
    public class LinkedListQueueExample {
        public static void main(String[] args) {
            Queue<String> queue = new LinkedList<>();
            queue.offer("A");
            queue.offer("B");
            System.out.println(queue.poll()); // 输出 A
            System.out.println(queue.peek()); // 输出 B
        }
    }
    

3.2 ArrayDeque

  • 底层结构:基于循环数组的双端队列。

  • 特点

    • 非线程安全:适合单线程环境。
    • 高性能:插入/删除操作复杂度为 O(1)
    • 不支持 null:添加 null 会抛出 NullPointerException
    • 适用场景:替代 Stack(LIFO)、高效双端操作。
  • 示例代码:

    import java.util.ArrayDeque;
    import java.util.Queue;
    
    public class ArrayDequeExample {
        public static void main(String[] args) {
            Queue<String> queue = new ArrayDeque<>();
            queue.offer("X");
            queue.offer("Y");
            System.out.println(queue.poll()); // 输出 X
            System.out.println(queue.peek()); // 输出 Y
        }
    }
    

3.3 PriorityQueue

  • 底层结构:基于最小堆的优先级队列。

  • 特点

    • 非线程安全:需外部同步。
    • 优先级排序:元素按自然顺序或自定义 Comparator 排序。
    • 不支持 null:添加 null 会抛出 NullPointerException
    • 适用场景:任务调度、按优先级处理。
  • 示例代码:

    import java.util.PriorityQueue;
    import java.util.Queue;
    
    public class PriorityQueueExample {
        public static void main(String[] args) {
            Queue<Integer> queue = new PriorityQueue<>();
            queue.offer(3);
            queue.offer(1);
            queue.offer(2);
            while (!queue.isEmpty()) {
                System.out.println(queue.poll()); // 输出 1, 2, 3
            }
        }
    }
    

3.4 LinkedBlockingQueue

  • 底层结构:基于链表的阻塞队列。

  • 特点

    • 线程安全:通过锁机制(ReentrantLock)实现。
    • 可设置容量:有界或无界(默认无界)。
    • 适用场景:生产者-消费者模型、多线程任务队列。
  • 示例代码:

    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    
    public class LinkedBlockingQueueExample {
        public static void main(String[] args) throws InterruptedException {
            BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);
            queue.put("A"); // 阻塞直到有空位
            queue.put("B");
            System.out.println(queue.take()); // 输出 A
            System.out.println(queue.take()); // 输出 B
        }
    }
    

3.5 ArrayBlockingQueue

  • 底层结构:基于数组的阻塞队列。

  • 特点

    • 线程安全:通过锁机制实现。
    • 固定容量:初始化时必须指定容量。
    • 适用场景:固定容量的阻塞队列(如资源池管理)。
  • 示例代码:

    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    
    public class ArrayBlockingQueueExample {
        public static void main(String[] args) throws InterruptedException {
            BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);
            queue.put("X"); // 阻塞直到有空位
            queue.put("Y");
            System.out.println(queue.take()); // 输出 X
            System.out.println(queue.take()); // 输出 Y
        }
    }
    

3.6 ConcurrentLinkedQueue

  • 底层结构:基于链表的无界非阻塞队列。

  • 特点

    • 线程安全:通过 CAS(Compare and Swap)算法实现无锁并发。
    • 高性能:适合高并发读写场景。
    • 适用场景:高并发环境下的非阻塞队列。
  • 示例代码:

    import java.util.concurrent.ConcurrentLinkedQueue;
    import java.util.Queue;
    
    public class ConcurrentLinkedQueueExample {
        public static void main(String[] args) {
            Queue<String> queue = new ConcurrentLinkedQueue<>();
            queue.offer("P");
            queue.offer("Q");
            System.out.println(queue.poll()); // 输出 P
            System.out.println(queue.peek()); // 输出 Q
        }
    }
    

3.7 DelayQueue

  • 底层结构:基于优先级队列的延迟队列。

  • 特点

    • 线程安全:通过锁机制实现。
    • 延迟元素:元素只有在指定延迟时间后才能被取出。
    • 适用场景:定时任务、缓存过期处理。
  • 示例代码:

    import java.util.concurrent.DelayQueue;
    import java.util.concurrent.Delayed;
    import java.util.concurrent.TimeUnit;
    
    class DelayedTask implements Delayed {
        private final long delayTime;
        private final long expireTime;
    
        public DelayedTask(long delaySeconds) {
            this.delayTime = delaySeconds;
            this.expireTime = System.currentTimeMillis() + delaySeconds * 1000;
        }
    
        @Override
        public long getDelay(TimeUnit unit) {
            long diff = expireTime - System.currentTimeMillis();
            return unit.convert(diff, TimeUnit.MILLISECONDS);
        }
    
        @Override
        public int compareTo(Delayed o) {
            return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
        }
    
        @Override
        public String toString() {
            return "DelayedTask{" +
                    "delayTime=" + delayTime +
                    '}';
        }
    }
    
    public class DelayQueueExample {
        public static void main(String[] args) throws InterruptedException {
            DelayQueue<DelayedTask> queue = new DelayQueue<>();
            queue.put(new DelayedTask(2)); // 延迟2秒
            queue.put(new DelayedTask(1)); // 延迟1秒
    
            while (!queue.isEmpty()) {
                System.out.println(queue.take()); // 输出 DelayedTask{delayTime=1} 然后 DelayedTask{delayTime=2}
            }
        }
    }
    

3.8 SynchronousQueue

  • 基本概念:
    SynchronousQueue 是 Java 并发包(java.util.concurrent)中的一种特殊阻塞队列,其核心特性如下:

    • 无缓冲设计:不存储任何元素,插入操作(put())必须等待另一个线程的删除操作(take()),反之亦然。
    • 直接传递:元素从生产者线程直接传递到消费者线程,无中间缓冲。
    • 线程安全:基于锁和条件变量实现线程安全。
    • 容量为0:严格来说,其容量为0,无法通过 offer() 方法非阻塞地插入元素。
  • 底层结构

    • Java 6 及之前:基于 TransferQueue 实现,使用 Transferer 接口处理元素的直接传递。
    • Java 7 及之后:优化为基于 TransferStack 的实现,使用无锁算法(如 CAS)提升性能。
  • 特点

    • 无容量:队列不存储任何元素,容量始终为 0。
    • 直接传递:插入操作(put)必须等待另一个线程的移除操作(take)完成,反之亦然。
    • 严格配对:每个生产者线程的插入操作必须与消费者线程的移除操作一一对应。
  • 示例代码:

    import java.util.concurrent.SynchronousQueue;
    
    public class SynchronousQueueExample {
        public static void main(String[] args) throws InterruptedException {
            SynchronousQueue<Integer> queue = new SynchronousQueue<>();
    
            // 生产者线程
            Thread producer = new Thread(() -> {
                try {
                    int data = 1;
                    System.out.println("Producer is putting: " + data);
                    queue.put(data); // 阻塞直到消费者接收数据
                    System.out.println("Producer put: " + data);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
    
            // 消费者线程
            Thread consumer = new Thread(() -> {
                try {
                    int data = queue.take(); // 阻塞直到生产者放入数据
                    System.out.println("Consumer received: " + data);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
    
            producer.start();
            consumer.start();
        }
    }
    

4. Deque接口与双端队列

4.1 Deque接口

  • 继承关系Deque 继承自 Queue,扩展了双端操作方法。
  • 核心方法
    • addFirst(E e) / offerFirst(E e):在队首添加元素。
    • addLast(E e) / offerLast(E e):在队尾添加元素。
    • removeFirst() / pollFirst():移除并返回队首元素。
    • removeLast() / pollLast():移除并返回队尾元素。

4.2 实现类

  • ArrayDeque:基于循环数组的双端队列。

  • LinkedList:基于双向链表的双端队列。

  • 示例代码:

    import java.util.ArrayDeque;
    import java.util.Deque;
    
    public class DequeExample {
        public static void main(String[] args) {
            Deque<String> deque = new ArrayDeque<>();
            deque.addFirst("A");
            deque.addLast("B");
            System.out.println(deque.pollFirst()); // 输出 A
            System.out.println(deque.pollLast());  // 输出 B
        }
    }
    

5. Queue的线程安全处理

5.1 使用 Collections.synchronizedQueue

  • LinkedListArrayDeque 进行同步包装。
Queue<String> syncQueue = Collections.synchronizedQueue(new LinkedList<>());

5.2 使用并发队列

  • LinkedBlockingQueueArrayBlockingQueueConcurrentLinkedQueue 等实现类。
  • 适用场景:多线程环境下的生产者-消费者模型、高并发任务队列。

6. Queue的性能对比

操作LinkedListArrayDequePriorityQueueLinkedBlockingQueueConcurrentLinkedQueue
添加/删除O(1)O(1)O(log n)O(1)(有界)O(1)(无锁)
查找O(n)O(1)(两端)O(1)(队首)O(1)(队首)O(1)(队首)
线程安全
允许 null

7. Queue的使用注意事项

7.1 选择合适的实现类

  • 简单队列:优先选择 LinkedListArrayDeque
  • 优先级排序:选择 PriorityQueue
  • 多线程环境:选择 LinkedBlockingQueueConcurrentLinkedQueue
  • 延迟处理:选择 DelayQueue

7.2 自定义对象的排序

  • 重写 compareTo 或提供 Comparator:用于 PriorityQueue 的优先级排序。
Queue<Person> queue = new PriorityQueue<>((a, b) -> Integer.compare(a.age, b.age));

7.3 性能优化

  • 预估容量:初始化时指定合适的容量,减少动态扩容次数。
  • 避免频繁中间操作:尽量在尾部进行增删操作。

8. Queue的典型应用场景

场景推荐实现类理由
任务调度PriorityQueue按优先级处理任务
生产者-消费者模型LinkedBlockingQueue线程安全,支持阻塞操作
高并发非阻塞队列ConcurrentLinkedQueue无锁设计,适合高并发
定时任务DelayQueue元素延迟处理
双端操作ArrayDeque高效的两端插入/删除

9. 总结

9.1 Queue的核心优势

  • 有序性:严格遵循 FIFO 或优先级排序。
  • 灵活性:支持多种实现类(链表、数组、阻塞队列等)。
  • 丰富的方法:提供入队、出队、查看队首等全套操作。

9.2 选择实现类的指导原则

  • 性能优先:根据操作类型选择 ArrayDequeLinkedListPriorityQueue
  • 线程安全:优先使用 LinkedBlockingQueueConcurrentLinkedQueue
  • 功能需求:根据是否需要优先级、延迟处理选择实现类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值