51mee - AI智能招聘平台Logo
模拟面试题目大全招聘中心会员专区

设计一个任务系统,支持多种任务类型(主线、支线、日常),如何高效处理任务队列,确保任务按优先级执行,并考虑并发场景下的线程安全。

多益网络程序类难度:中等

答案

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) 【追问清单】:

  • 问题1:任务优先级是否可以动态调整?(如主线任务完成进度影响优先级?)
    回答要点:可以,通过在任务类中增加动态优先级字段,或维护优先级更新机制(如进度达到阈值时调用setPriority调整,调度器重新排序队列)。
  • 问题2:任务有循环依赖时如何处理?(如任务A依赖B,B依赖A?)
    回答要点:在检查依赖时检测循环,若发现循环依赖则标记为无效,不执行,并记录错误日志。
  • 问题3:线程池大小如何确定?(任务数量多时,线程池过大或过小的影响?)
    回答要点:根据系统负载和任务类型动态调整,主线任务用较小线程池(核心线程数=CPU核心数),支线和日常任务用较大线程池(核心+最大线程数),避免资源浪费或响应慢。
  • 问题4:任务超时或失败如何处理?(超时是否重试?重试策略是什么?)
    回答要点:设置超时时间,超时后放入失败队列,根据失败次数决定是否重试(如3次后放弃),重试间隔采用指数退避(如第一次1秒,第二次2秒,第三次4秒)。
  • 问题5:任务队列内存效率如何保证?(大量任务时内存占用问题?)
    回答要点:定期清理过期任务(如日常任务有效期),或设置队列最大容量,超限拒绝新任务,避免内存溢出。

7) 【常见坑/雷区】:

  • 坑1:忽略任务状态管理,导致队列中存在重复或无效任务,影响系统效率。
  • 坑2:未处理任务依赖,导致支线任务在主线任务未完成时执行,引发错误。
  • 坑3:超时重试策略不当,如无限重试导致资源浪费或死循环。
  • 坑4:线程池大小设置不当,过大导致线程竞争,过小导致任务积压。
  • 坑5:优先级队列线程安全实现错误,如普通队列未加锁,导致并发下任务顺序混乱。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1