Java里如何使用PriorityBlockingQueue实现优先级队列

来源:PHP编程网作者:日本程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《Java里如何使用PriorityBlockingQueue实现优先级队列》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java里如何使用PriorityBlockingQueue实现优先级队列》有用,将其分享出去将是对创作者最好的鼓励。

PriorityBlockingQueue是Java并发包java.util.concurrent下的一个线程安全阻塞队列,它支持按照元素的优先级进行排序,内部基于二叉堆结构实现,默认情况下元素按照自然顺序升序排列,也可以通过自定义比较器指定排序规则。它不允许插入null元素,并且是 unbounded 队列,理论上可以一直添加元素直到内存耗尽。

Java里如何使用PriorityBlockingQueue实现优先级队列

PriorityBlockingQueue核心特性

  • 线程安全:所有入队出队操作都通过锁机制保证线程安全,适合多线程并发场景
  • 优先级排序:元素会按照指定规则排序,队头元素永远是优先级最高(或最低,取决于排序规则)的元素
  • 阻塞特性:当队列为空时,获取元素的操作会阻塞等待,直到队列中有新元素加入
  • 无界队列:没有固定容量限制,插入操作不会因为队列满而阻塞

基本操作方法

构造方法

PriorityBlockingQueue提供了多个构造方法,常用的有以下几种:

// 默认构造方法,初始容量为11,按照元素自然顺序排序
PriorityBlockingQueue<Integer> queue1 = new PriorityBlockingQueue<>();

// 指定初始容量的构造方法
PriorityBlockingQueue<Integer> queue2 = new PriorityBlockingQueue<>(20);

// 指定初始容量和自定义比较器的构造方法
PriorityBlockingQueue<Integer> queue3 = new PriorityBlockingQueue<>(20, (a, b) -> b - a);

常用API说明

方法名作用特性说明
add(E e)添加元素到队列成功返回true,插入null会抛NullPointerException
offer(E e)添加元素到队列成功返回true,插入null会抛NullPointerException
put(E e)添加元素到队列由于是无界队列,该方法不会阻塞,效果和add一致
peek()获取队头元素但不移除队列为空返回null
poll()获取并移除队头元素队列为空返回null
take()获取并移除队头元素队列为空时会阻塞等待,直到有元素可用
size()获取队列元素数量由于遍历过程需要加锁,该方法开销比普通集合大

自定义元素优先级规则

如果要存储自定义类型的元素,需要让元素实现Comparable接口重写compareTo方法,或者在构造PriorityBlockingQueue时传入自定义Comparator比较器,否则会抛出ClassCastException

方式一:元素实现Comparable接口

以任务类为例,假设任务有优先级字段,优先级数值越小优先级越高:

import java.util.concurrent.PriorityBlockingQueue;

// 自定义任务类,实现Comparable接口
class Task implements Comparable<Task> {
    private String name;
    private int priority; // 优先级,数值越小优先级越高

    public Task(String name, int priority) {
        this.name = name;
        this.priority = priority;
    }

    // 重写compareTo方法,按照优先级升序排列
    @Override
    public int compareTo(Task o) {
        return Integer.compare(this.priority, o.priority);
    }

    @Override
    public String toString() {
        return "Task{name='" + name + "', priority=" + priority + "}";
    }
}

public class PriorityBlockingQueueDemo {
    public static void main(String[] args) {
        // 创建优先级阻塞队列
        PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();

        // 添加不同优先级的任务
        queue.add(new Task("低优先级任务", 3));
        queue.add(new Task("高优先级任务", 1));
        queue.add(new Task("中优先级任务", 2));

        // 依次取出任务,验证优先级排序
        while (!queue.isEmpty()) {
            System.out.println(queue.poll());
        }
    }
}

方式二:传入自定义Comparator比较器

如果不想修改自定义类的代码,可以在构造队列时传入比较器:

import java.util.Comparator;
import java.util.concurrent.PriorityBlockingQueue;

class Task {
    private String name;
    private int priority;

    public Task(String name, int priority) {
        this.name = name;
        this.priority = priority;
    }

    public int getPriority() {
        return priority;
    }

    @Override
    public String toString() {
        return "Task{name='" + name + "', priority=" + priority + "}";
    }
}

public class PriorityBlockingQueueDemo2 {
    public static void main(String[] args) {
        // 传入自定义比较器,按照优先级升序排列
        PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>(10, Comparator.comparingInt(Task::getPriority));

        queue.add(new Task("低优先级任务", 3));
        queue.add(new Task("高优先级任务", 1));
        queue.add(new Task("中优先级任务", 2));

        while (!queue.isEmpty()) {
            System.out.println(queue.poll());
        }
    }
}

多线程场景使用示例

PriorityBlockingQueue的阻塞特性非常适合生产者消费者模型,下面的示例模拟多个生产者提交不同优先级的任务,单个消费者按照优先级处理任务:

import java.util.concurrent.PriorityBlockingQueue;

class Task implements Comparable<Task> {
    private String name;
    private int priority;

    public Task(String name, int priority) {
        this.name = name;
        this.priority = priority;
    }

    @Override
    public int compareTo(Task o) {
        return Integer.compare(this.priority, o.priority);
    }

    @Override
    public String toString() {
        return "Task{name='" + name + "', priority=" + priority + "}";
    }
}

public class MultiThreadDemo {
    public static void main(String[] args) {
        PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();

        // 启动3个生产者线程,提交不同优先级的任务
        for (int i = 0; i < 3; i++) {
            int producerId = i;
            new Thread(() -> {
                for (int j = 0; j < 3; j++) {
                    int priority = (int) (Math.random() * 5) + 1;
                    Task task = new Task("生产者" + producerId + "的任务" + j, priority);
                    queue.put(task);
                    System.out.println("生产者" + producerId + "提交了任务:" + task);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }).start();
        }

        // 启动1个消费者线程,处理任务
        new Thread(() -> {
            while (true) {
                try {
                    // take方法会阻塞,直到队列中有任务
                    Task task = queue.take();
                    System.out.println("消费者处理了任务:" + task);
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }).start();
    }
}

注意事项

  • PriorityBlockingQueue的迭代器不保证按照优先级顺序遍历元素,如果需要按顺序遍历,可以先取出所有元素再排序
  • 自定义比较规则时要保证比较逻辑的一致性,避免出现比较结果矛盾的情况,否则可能导致堆结构异常
  • 虽然是无界队列,但插入元素时如果内存不足还是会抛出OutOfMemoryError
  • 批量添加元素时,如果使用addAll方法,会逐个添加元素并调整堆结构,效率比逐个添加高,但依然要保证所有元素都符合排序规则

PriorityBlockingQueueJava优先级队列线程安全队列compareTo方法阻塞队列修改时间:2026-07-17 21:30:22

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。