🔥 本文深入剖析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());
});
为什么普通队列不够用?
相比普通队列,优先队列具有以下关键优势:
- 自动排序:插入元素时自动维护优先级顺序
- 高效获取:O(1)时间复杂度获取最高优先级元素
- 动态调整:可以随时添加新元素,优先级顺序自动调整
普通队列只能按照"先进先出"原则处理元素,而实际应用中,我们常常需要"重要的先处理",这正是优先队列的价值所在。
实际使用注意事项
- 优先级定义要明确:确保Comparator满足全序关系
- 动态优先级处理:对于优先级会变化的场景,需要特殊处理
- 大数据量优化:考虑限制队列大小,避免内存问题
优先队列就像生活中的"VIP通道",为重要的数据提供了一条"快速通道",让系统能够更智能地处理各种任务。无论是系统底层的资源调度,还是应用层的业务逻辑,当我们需要处理带有优先级概念的数据时,优先队列都是一个强大且高效的工具。
4.2 实战案例:任务调度系统的实现
让我们通过一个实际案例来理解优先队列的应用。假设我们需要设计一个简单但实用的任务调度系统,它能够根据任务优先级和截止时间来合理安排执行顺序。
业务需求分析
我们的任务调度系统需要满足以下需求:
- 支持不同优先级的任务
- 考虑任务的截止时间
- 能够动态添加新任务
- 支持任务取消功能
- 提供任务执行状态查询
核心代码实现
首先,定义任务类:
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()<