设计一个异步任务执行框架:利用多线程执行耗时任务并在完成后通知主线程
🚀 设计一个异步任务执行框架:利用多线程执行耗时任务并在完成后通知主线程
异步任务执行框架的本质是将任务提交给线程池异步执行,通过Future、Callback、CompletableFuture、事件总线或者消息通知机制回调主线程,实现任务状态跟踪、结果获取和异常处理。其核心组成包括任务提交器、线程池、任务队列、结果存储器、回调机制以及状态管理模块。
1️⃣ 问题背景
在企业级系统开发中,经常遇到大量耗时操作,例如文件导出、Excel生成、PDF生成、短信发送、邮件推送、AI计算、视频转码、报表统计等。
如果这些操作直接在主线程执行,那么用户请求会长时间阻塞,接口响应时间急剧增加,严重影响用户体验。
例如:
- 生成10万条数据的Excel文件需要30秒
- 调用第三方接口需要10秒
- 批量发送短信需要20秒
- 统计全校就业数据需要数分钟
此时最佳方案就是异步化处理:
因此很多大型系统都会设计统一的异步任务执行框架,实现任务调度、状态管理和结果通知。
2️⃣ 核心原理
异步任务框架本质上采用生产者消费者模型。
主线程负责提交任务,相当于生产者。
线程池负责执行任务,相当于消费者。
任务完成后通过回调机制通知主线程。
用户请求
↓
TaskManager
↓
任务队列 BlockingQueue
↓
ThreadPoolExecutor
↓
执行任务
↓
Future / Callback
↓
通知主线程
这里最关键的技术点包括:
- 线程池管理
- 任务队列管理
- 任务状态维护
- 异步结果获取
- 异常处理机制
- 任务回调机制
3️⃣ 数据结构分析
任务对象设计
String taskId;
TaskStatus status;
Object result;
Exception exception;
Long createTime;
Long finishTime;
}
任务状态设计
WAITING,
RUNNING,
SUCCESS,
FAILED
}
任务缓存结构
通常采用ConcurrentHashMap存储任务状态。
Key为任务ID,Value为任务对象。
这样可以快速查询任务执行状态。
任务队列
任务队列通常使用BlockingQueue。
线程池从队列中不断获取任务执行。
4️⃣ 算法分析
异步任务执行框架核心算法非常简单。
↓
② 放入任务队列
↓
③ 工作线程获取任务
↓
④ 执行业务逻辑
↓
⑤ 保存执行结果
↓
⑥ 触发回调通知
时间复杂度分析:
- 任务提交:O(1)
- 任务查询:O(1)
- 任务回调:O(1)
- 线程调度:O(1)
整体性能主要取决于线程池大小和任务执行时间。
5️⃣ 执行流程
第一步:构建线程池
new ThreadPoolExecutor(
10,
50,
60,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000)
);
第二步:提交任务
Thread.sleep(5000);
return "执行完成";
});
第三步:监听结果
Future.get()会阻塞等待结果。
实际生产环境通常采用回调机制。
CompletableFuture回调通知
System.out.println(Thread.currentThread().getName());
return "订单创建成功";
}, executor).thenAccept(result -> {
System.out.println(Thread.currentThread().getName());
System.out.println(result);
});
这样任务执行完成后自动触发通知。
6️⃣ 实际案例
案例一:Excel导出
用户点击导出按钮。
系统立即返回任务ID。
返回:taskId=10001
后台线程池开始生成Excel。
完成后上传OSS。
然后发送站内信通知用户。
↓
生成下载链接
↓
发送消息通知
↓
用户下载文件
案例二:就业分析报表生成
用户发起就业质量分析。
统计逻辑涉及数百万数据。
主线程只负责创建任务。
后台线程池完成分析。
最终通过WebSocket通知前端。
案例三:AI模型推理
大模型推理耗时较长。
通常采用异步任务模式。
任务完成后通过消息队列或者SSE返回结果。
7️⃣ 优缺点分析
优点
- 提高系统响应速度
- 减少请求阻塞
- 提升服务器吞吐量
- 支持任务状态跟踪
- 支持失败重试机制
- 支持任务优先级调度
缺点
- 系统复杂度提高
- 任务状态维护成本增加
- 异常处理更加复杂
- 线程池参数需要调优
- 容易出现任务堆积
8️⃣ 面试常见问题
面试题1:为什么不用new Thread?
线程创建和销毁成本较高。
线程池能够复用线程,提高资源利用率。
面试题2:Future和CompletableFuture区别?
- Future只能获取结果
- CompletableFuture支持链式编排
- CompletableFuture支持回调
- CompletableFuture支持任务组合
面试题3:如何通知主线程?
- Future.get()
- Callback回调
- CompletableFuture
- WebSocket
- SSE推送
- 消息队列
面试题4:如何保证任务不丢失?
可以将任务持久化到数据库或者Redis。
系统重启后重新加载任务继续执行。
面试题5:如何支持失败重试?
try{
execute();
break;
}catch(Exception e){
retry++;
}
}
面试题6:大型系统如何设计?
阿里、字节、腾讯等大厂通常采用:
- 任务中心
- 线程池集群
- Kafka消息队列
- Redis状态存储
- WebSocket通知
- 分布式调度平台
最终形成统一异步任务平台。
9️⃣ 总结
📌 异步任务框架核心组件:
- TaskManager任务管理器
- ThreadPoolExecutor线程池
- BlockingQueue任务队列
- ConcurrentHashMap状态缓存
- Future/CompletableFuture结果获取
- Callback回调通知机制
🎯 典型执行流程:
提交任务 → 放入队列 → 线程池执行 → 保存结果 → 回调通知 → 用户获取结果
🚀 企业级最佳实践:
对于中小系统,可以采用ThreadPoolExecutor + CompletableFuture实现异步框架;对于大型分布式系统,建议采用Kafka + Redis + WebSocket + 任务调度中心构建统一异步任务平台,实现任务持久化、失败重试、状态追踪和实时通知能力。
相关文章
-
在github上创建一个项目
在github上创建一个项目
NEW个对象 2024-10-03
-
Spring Cloud与Dubbo的冲突吗?
之前别人问我Spring Cloud与Dubbo的区别。 我这样回答: Spring Cloud是解决分布式系统开发的工具,Dubbo是一个RPC框架,两者有本质上的区别。
NEW个对象 2024-11-02
-
synchronized 和 ReentrantLock 的区别详解
synchronized 和 ReentrantLock 的区别详解
NEW个对象 2026-06-13