【Java集合夜话】第8篇下:PriorityQueue优先队列详解,从源码到实战,一文吃透堆数据结构(建议收藏)

🔥 本文深入剖析Java中的优先队列PriorityQueue,从实战应用、性能优化到面试技巧,带你全面掌握这个重要的数据结构。由于内容较多,分为上下两篇,本篇是下篇,主要讲解实战应用和进阶技巧。

📚博主强推高手观看系列专栏

积极

4. 实战应用

4.1 常见应用场景:为什么需要优先队列?

在我们的日常生活中,"优先"二字无处不在。医院急诊室里,心脏病患者比感冒患者优先就诊;高速公路上,救护车比私家车优先通行。这种"优先级"的概念,在编程世界中同样重要,而优先队列正是为解决这类问题而生的。

核心应用场景

1. 任务调度系统

操作系统需要决定哪个进程下一个获得CPU时间片,这时就需要考虑进程的优先级。

// 操作系统进程调度简化示例
PriorityQueue<Process> readyQueue = new PriorityQueue<>((p1, p2) -> 
    p1.getPriority() - p2.getPriority());

// 系统进程(高优先级)
readyQueue.offer(new Process("SystemService", 1));
// 前台应用(中优先级)
readyQueue.offer(new Process("UserApp", 5));

// 调度器会先处理SystemService,然后是UserApp

2. 数据包路由

在网络设备中,数据包需要根据优先级进行排队和转发。

// 创建路由队列,高优先级先路由
PriorityQueue<Packet> routingQueue = new PriorityQueue<>((p1, p2) -> 
    p2.getPriority() - p1.getPriority());

// VoIP数据包(高优先级)
routingQueue.offer(new Packet(10, voipData));
// 网页浏览数据包(中优先级)
routingQueue.offer(new Packet(5, webData));

3. 医疗系统分诊

在医院的急诊室,病人不是按照到达顺序,而是按照病情严重程度进行处理。

// 患者分诊队列
PriorityQueue<Patient> emergencyRoom = new PriorityQueue<>((p1, p2) -> {
   
   
    // 首先比较紧急程度
    if (p1.getEmergencyLevel() != p2.getEmergencyLevel()) {
   
   
        return p1.getEmergencyLevel() - p2.getEmergencyLevel();
    }
    // 紧急程度相同,先到先处理
    return (int)(p1.getArrivalTime() - p2.getArrivalTime());
});
为什么普通队列不够用?

相比普通队列,优先队列具有以下关键优势:

  1. 自动排序:插入元素时自动维护优先级顺序
  2. 高效获取:O(1)时间复杂度获取最高优先级元素
  3. 动态调整:可以随时添加新元素,优先级顺序自动调整

普通队列只能按照"先进先出"原则处理元素,而实际应用中,我们常常需要"重要的先处理",这正是优先队列的价值所在。

实际使用注意事项
  1. 优先级定义要明确:确保Comparator满足全序关系
  2. 动态优先级处理:对于优先级会变化的场景,需要特殊处理
  3. 大数据量优化:考虑限制队列大小,避免内存问题

优先队列就像生活中的"VIP通道",为重要的数据提供了一条"快速通道",让系统能够更智能地处理各种任务。无论是系统底层的资源调度,还是应用层的业务逻辑,当我们需要处理带有优先级概念的数据时,优先队列都是一个强大且高效的工具。

4.2 实战案例:任务调度系统的实现

让我们通过一个实际案例来理解优先队列的应用。假设我们需要设计一个简单但实用的任务调度系统,它能够根据任务优先级和截止时间来合理安排执行顺序。

业务需求分析

我们的任务调度系统需要满足以下需求:

  1. 支持不同优先级的任务
  2. 考虑任务的截止时间
  3. 能够动态添加新任务
  4. 支持任务取消功能
  5. 提供任务执行状态查询
核心代码实现

首先,定义任务类:

public class ScheduledTask implements Comparable<ScheduledTask> {
   
   
    private String id;          // 任务ID
    private String name;        // 任务名称
    private int priority;       // 优先级(1-10),1最高
    private long deadlineMs;    // 截止时间(毫秒时间戳)
    private long durationMs;    // 预计执行时间
    private TaskStatus status;  // 任务状态
    
    // 枚举:任务状态
    public enum TaskStatus {
   
   
        PENDING, RUNNING, COMPLETED, CANCELLED
    }
    
    public ScheduledTask(String id, String name, int priority, long deadlineMs, long durationMs) {
   
   
        this.id = id;
        this.name = name;
        this.priority = priority;
        this.deadlineMs = deadlineMs;
        this.durationMs = durationMs;
        this.status = TaskStatus.PENDING;
    }
    
    // 实现优先级比较
    @Override
    public int compareTo(ScheduledTask other) {
   
   
        // 首先比较优先级
        if (this.priority != other.priority) {
   
   
            return this.priority - other.priority;
        }
        // 优先级相同时,比较截止时间
        return Long.compare(this.deadlineMs, other.deadlineMs);
    }
    
    // getter和setter方法
    public String getId() {
   
    return id; }
    public String getName() {
   
    return name; }
    public int getPriority() {
   
    return priority; }
    public long getDeadlineMs() {
   
    return deadlineMs; }
    public long getDurationMs() {
   
    return durationMs; }
    public TaskStatus getStatus() {
   
    return status; }
    public void setStatus(TaskStatus status) {
   
    this.status = status; }
    
    @Override
    public String toString() {
   
   
        return String.format("Task[id=%s, name=%s, priority=%d, deadline=%d, status=%s]", 
                            id, name, priority, deadlineMs, status);
    }
}

接下来,实现调度器:

public class TaskScheduler {
   
   
    // 任务队列
    private PriorityQueue<ScheduledTask> taskQueue;
    // 任务ID映射表,用于快速查找和取消任务
    private Map<String, ScheduledTask> taskMap;
    // 工作线程
    private Thread workerThread;
    // 运行标志
    private volatile boolean running;
    
    public TaskScheduler() {
   
   
        this.taskQueue = new PriorityQueue<>();
        this.taskMap = new HashMap<>();
        this.running = false;
    }
    
    // 添加任务
    public synchronized boolean scheduleTask(ScheduledTask task) {
   
   
        if (task == null || taskMap.containsKey(task.getId())) {
   
   
            return false;
        }
        
        taskQueue.offer(task);
        taskMap.put(task.getId(), task);
        
        System.out.println("任务已添加: " + task.getName());
        return true;
    }
    
    // 取消任务
    public synchronized boolean cancelTask(String taskId) {
   
   
        ScheduledTask task = taskMap.get(taskId);
        if (task == null || task.getStatus() != ScheduledTask.TaskStatus.PENDING) {
   
   
            return false;
        }
        
        task.setStatus(ScheduledTask.TaskStatus.CANCELLED);
        System.out.println("任务已取消: " + task.getName());
        return true;
    }
    
    // 获取任务状态
    public TaskStatus getTaskStatus(String taskId) {
   
   
        ScheduledTask task = taskMap.get(taskId);
        return task != null ? task.getStatus() : null;
    }
    
    // 启动调度器
    public synchronized void start() {
   
   
        if (running) {
   
   
            return;
        }
        
        running = true;
        workerThread = new Thread(() -> {
   
   
            while (running) {
   
   
                try {
   
   
                    processNextTask();
                    // 简单起见,这里用sleep模拟处理间隔
                    Thread.sleep(100);
                } catch (InterruptedException e) {
   
   
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });
        
        workerThread.start();
        System.out.println("调度器已启动");
    }
    
    // 停止调度器
    public synchronized void stop() {
   
   
        running = false;
        if (workerThread != null) {
   
   
            workerThread.interrupt();
            workerThread = null;
        }
        System.out.println("调度器已停止");
    }
    
    // 处理下一个任务
    private synchronized void processNextTask() {
   
   
        // 清理已取消的任务
        taskQueue.removeIf(task -> task.getStatus() == ScheduledTask.TaskStatus.CANCELLED);
        
        ScheduledTask task = taskQueue.poll();
        if (task == null) {
   
   
            return;
        }
        
        // 检查任务是否已取消
        if (task.getStatus() == ScheduledTask.TaskStatus.CANCELLED) {
   
   
            return;
        }
        
        // 执行任务
        task.setStatus(ScheduledTask.TaskStatus.RUNNING);
        System.out.println("开始执行任务: " + task.getName());
        
        // 模拟任务执行
        try {
   
   
            Thread.sleep(task.getDurationMs());
            task.setStatus(ScheduledTask.TaskStatus.COMPLETED);
            System.out.println("任务执行完成: " + task.getName());
        } catch (InterruptedException e) {
   
   
            Thread.currentThread().interrupt();
        }
    }
}
使用示例

下面是一个简单的使用示例:

public class TaskSchedulerDemo {
   
   
    public static void main(String[] args) throws InterruptedException {
   
   
        // 创建调度器
        TaskScheduler scheduler = new TaskScheduler();
        
        // 启动调度器
        scheduler.start()<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值