视频看了几百小时还迷糊?关注我,几分钟让你秒懂!(发点评论可以给博主加热度哦)
在现代 Java Web 开发中,异步处理是提升系统性能、优化用户体验的关键手段。比如用户注册后发送邮件、订单创建后调用第三方接口、日志异步写入等场景,都不应阻塞主线程。
Spring Boot 原生提供了 @Async 注解来实现异步,但存在线程池配置复杂、异常难捕获、任务结果难追踪等问题。这时候,AsyncTool 就派上用场了!
一、什么是 AsyncTool?
AsyncTool 是一个轻量级、高性能的 Java 异步任务编排工具库,由国内开发者开源。它支持:
- 多任务并行执行
- 任务结果聚合
- 异常统一处理
- 自定义线程池
- 链式调用 & 回调机制
相比 Spring 的 @Async,AsyncTool 更灵活、更可控、更适合复杂业务场景。
二、需求场景举例
假设你正在开发一个“用户下单”功能,需要同时做三件事:
如果用同步方式,整个下单可能要 1~2 秒;而用异步并行处理,主流程只需几十毫秒!
三、引入依赖(Maven)
<dependency>
<groupId>com.github.dadiyang</groupId>
<artifactId>async-tool</artifactId>
<version>1.0.6</version>
</dependency>
四、正确用法示例(Spring Boot + AsyncTool)
1. 配置自定义线程池(推荐)
@Configuration
public class AsyncConfig {
@Bean("customAsyncExecutor")
public ExecutorService customAsyncExecutor() {
return new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
60L, TimeUnit.SECONDS, // 空闲线程存活时间
new LinkedBlockingQueue<>(100), // 任务队列
new ThreadFactoryBuilder().setNamePrefix("async-tool-pool-").build(),
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:主线程执行
);
}
}
2. 服务层使用 AsyncTool 并行执行任务
@Service
@Slf4j
public class OrderService {
@Autowired
private ExecutorService customAsyncExecutor;
public String createOrder(Long userId, String product) {
log.info("开始创建订单,用户ID: {}", userId);
// 主流程:保存订单(同步)
String orderId = saveOrderToDB(userId, product);
// 异步并行执行其他任务
AsyncUtil.run(() -> sendSms(userId), customAsyncExecutor)
.thenRun(() -> addPoints(userId), customAsyncExecutor)
.exceptionally(throwable -> {
log.error("异步任务出错", throwable);
return null;
});
log.info("订单创建完成,ID: {}", orderId);
return orderId;
}
private String saveOrderToDB(Long userId, String product) {
// 模拟数据库操作
try { Thread.sleep(50); } catch (InterruptedException e) { }
return "ORDER_" + System.currentTimeMillis();
}
private void sendSms(Long userId) {
log.info("【异步】发送短信给用户: {}", userId);
// 模拟网络调用
try { Thread.sleep(200); } catch (InterruptedException e) { }
// 故意抛个异常测试
if (userId == 999L) {
throw new RuntimeException("短信服务不可用");
}
}
private void addPoints(Long userId) {
log.info("【异步】为用户 {} 增加积分", userId);
try { Thread.sleep(150); } catch (InterruptedException e) { }
}
}
3. Controller 调用
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/create")
public ResponseEntity<String> createOrder(@RequestParam Long userId,
@RequestParam String product) {
String orderId = orderService.createOrder(userId, product);
return ResponseEntity.ok(orderId);
}
}
五、运行效果
请求:
POST /order/create?userId=123&product=手机
日志输出(顺序可能不同):
开始创建订单,用户ID: 123
订单创建完成,ID: ORDER_1700000000000
【异步】发送短信给用户: 123
【异步】为用户 123 增加积分
主线程几乎瞬间返回,异步任务在后台执行,互不影响!
六、反例:错误使用方式(避坑指南)
❌ 反例1:直接使用 new Thread().start()
// 千万别这么干!
new Thread(() -> sendSms(userId)).start();
问题:
- 无法控制线程数量,容易 OOM
- 异常无法捕获,静默失败
- 没有资源回收,浪费系统资源
❌ 反例2:滥用 Spring @Async 且不配置线程池
@Async // 默认使用 SimpleAsyncTaskExecutor(每次新建线程!)
public void sendEmail(String email) {
// …
}
问题:
- 每次调用都新建线程,高并发下服务器崩溃
- 无法统一管理、监控、限流
❌ 反例3:异步任务中未处理异常
AsyncUtil.run(() -> {
// 可能抛异常的操作
riskyOperation();
}, executor);
// 如果 riskyOperation 抛异常,这里完全不知道!
正确做法:务必使用 .exceptionally() 或 try-catch 包裹
七、注意事项(重要!)
不要在异步任务中处理事务 Spring 的事务是基于 ThreadLocal 的,异步线程无法继承主线程的事务上下文。如需事务,请在异步方法内部开启新事务(@Transactional(propagation = Propagation.REQUIRES_NEW))。
线程池必须自定义 避免使用默认线程池,务必根据业务量设置合理的 corePoolSize、queueSize 和拒绝策略。
避免在异步任务中使用 RequestContextHolder 异步线程拿不到 HTTP 请求上下文(如用户信息、traceId),如需传递,需手动通过 ThreadLocal 或参数传入。
任务不要无限堆积 如果任务生产速度 > 消费速度,队列会爆满。建议配合监控(如 Micrometer)观察队列长度。
测试时注意线程切换 单元测试中,异步任务可能还没执行完就结束了。可使用 CountDownLatch 或 CompletableFuture.get() 等待。
八、进阶:获取多个异步任务结果
CompletableFuture<String> future1 = AsyncUtil.call(() -> getSmsResult(), executor);
CompletableFuture<Integer> future2 = AsyncUtil.call(() -> getPoints(), executor);
// 等待所有完成
CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2);
all.join(); // 阻塞等待
String sms = future1.get();
Integer points = future2.get();
总结
| new Thread() | 简单 | 不可控、危险 |
| Spring @Async | 集成方便 | 配置复杂、异常难处理 |
| AsyncTool | 灵活、安全、高性能 | 需额外引入依赖 |
结论:对于需要多任务并行、结果聚合、异常兜底的场景,强烈推荐使用 AsyncTool!
视频看了几百小时还迷糊?关注我,几分钟让你秒懂!(发点评论可以给博主加热度哦)

