
1) 【一句话结论】:采用线程安全的优先级队列作为核心调度器,结合任务状态管理(完成/失败/重试)、依赖关系检查,确保高优先级任务优先执行,并支持并发场景下的线程安全与任务生命周期管理。
2) 【原理/概念讲解】:老师:设计任务系统,核心是“优先级调度+状态流转+依赖处理+线程安全”。优先级队列按任务类型(主线、支线、日常)映射不同优先级(主线最高),插入时根据优先级排序,取出时总是最高优先级。任务执行后,根据结果更新状态(成功则移除队列,失败则进入重试队列,重试次数不超过3次)。任务类维护依赖列表,调度器执行前检查依赖是否全部完成。线程安全用ConcurrentLinkedPriorityQueue,避免并发下队列混乱。类比:就像医院急诊系统,急诊(高优先级)先处理,普通门诊后,同时多个医生(线程)可以接诊或添加病人(任务),系统不会乱。
3) 【对比与适用场景】:
| 实现方式 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
普通优先级队列(如PriorityQueue) | 基于堆的优先级队列,非线程安全 | 单线程,插入/取出O(log n),需手动加锁 | 单线程任务调度 | 并发环境下需额外加锁,易导致性能下降 |
并发优先级队列(如ConcurrentLinkedPriorityQueue) | 基于无锁链表实现的线程安全优先级队列 | 无锁,插入/取出O(1)(近似),支持高并发 | 多线程任务调度(如游戏任务系统) | 优先级可能因无锁导致轻微延迟,需测试 |
| 带状态的自定义优先级队列 | 手动实现加锁的优先级队列,维护任务状态(完成/失败) | 可定制状态流转逻辑,支持重试机制 | 复杂任务系统(如需要重试、依赖检查) | 实现复杂,易出错,需额外维护状态 |
4) 【示例】:
// 任务类,包含状态、依赖、超时等
class Task {
String id;
String type; // "主线", "支线", "日常"
int priority; // 1(最高)到3(最低)
Object payload;
TaskState state; // 0:待执行, 1:执行中, 2:成功, 3:失败, 4:重试中
List<Task> dependencies; // 依赖任务列表
long timeout; // 超时时间(ms)
int retryCount; // 重试次数
}
enum TaskState { PENDING, RUNNING, SUCCESS, FAILURE, RETRYING }
// 优先级映射
Map<String, Integer> priorityMap = new HashMap<>();
priorityMap.put("主线", 1);
priorityMap.put("支线", 2);
priorityMap.put("日常", 3);
class TaskQueue {
private final ConcurrentLinkedPriorityQueue<Task> queue;
private final Map<String, Task> taskMap;
public TaskQueue() {
this.queue = new ConcurrentLinkedPriorityQueue<>(Comparator.comparingInt(t -> t.priority).reversed());
this.taskMap = new ConcurrentHashMap<>();
}
public void addTask(Task task) {
if (!checkDependencies(task)) return;
queue.offer(task);
taskMap.put(task.id, task);
}
private boolean checkDependencies(Task task) {
for (Task dep : task.dependencies) {
if (taskMap.get(dep.id).state != TaskState.SUCCESS) return false;
}
return true;
}
public Task executeNext() {
Task task = queue.poll();
if (task == null) return null;
task.state = TaskState.RUNNING;
boolean result = executeTask(task);
if (result) {
task.state = TaskState.SUCCESS;
queue.remove(task);
taskMap.remove(task.id);
} else {
task.state = TaskState.FAILURE;
if (task.retryCount > 0) {
task.retryCount--;
task.state = TaskState.RETRYING;
queue.offer(task);
} else {
task.state = TaskState.FAILURE;
}
}
return task;
}
private boolean executeTask(Task task) {
// 模拟业务逻辑,80%成功概率
return Math.random() > 0.2;
}
}
// 使用示例
TaskQueue queue = new TaskQueue();
Task mainTask = new Task("1", "主线", 1, "主线任务", TaskState.PENDING, new ArrayList<>(), 5000, 3);
Task branchTask = new Task("2", "支线", 2, "支线任务", TaskState.PENDING, Arrays.asList(mainTask), 3000, 2);
queue.addTask(mainTask);
queue.addTask(branchTask);
while (!queue.isEmpty()) {
Task task = queue.executeNext();
System.out.println("执行任务: " + task.id + ", 类型: " + task.type + ", 状态: " + task.state);
}
5) 【面试口播版答案】:面试官您好,设计任务系统的话,核心是解决“优先级调度”“任务状态管理”“依赖关系处理”和“线程安全”。首先,我会用线程安全的优先级队列作为核心,任务按类型(主线、支线、日常)映射不同优先级(主线最高),插入队列时根据优先级排序。为了线程安全,用ConcurrentLinkedPriorityQueue,支持高并发下的无锁操作。任务执行后,根据结果更新状态:成功则从队列移除,失败则进入重试队列(重试次数不超过3次,超时后重试间隔指数退避)。同时,任务类维护依赖列表,调度器执行前检查依赖是否全部完成(比如支线任务依赖主线任务完成)。这样既能保证高优先级任务优先执行,又能处理并发场景,确保任务生命周期(待执行、执行中、成功、失败、重试)有序流转。总结来说,就是优先级队列结合状态管理、依赖检查和线程安全机制,确保任务按优先级有序执行,并发安全,且具备鲁棒性。
6) 【追问清单】:
setPriority调整,调度器重新排序队列)。7) 【常见坑/雷区】: