很多后端同学在学习并发时都会经历三个阶段:
@Async用不起来- 线程池参数不会调
- 不知道什么时候该用 MQ
如果你也卡在这三点,这篇文章就是为你准备的。
本文将从 实战工程视角,一文打通:
- @Async 失效原因
- 线程池参数调优
- 线程池 vs MQ 选型思维
目标只有一句话:
不只是会用异步,而是理解"什么时候用、怎么用、用到什么程度"。
第一部分:@Async 为什么会失效?
这是 90% 初学者踩的坑。
1. 没有开启异步支持
错误:
java
@SpringBootApplication
public class App {}
正确:
java
@EnableAsync
@SpringBootApplication
public class App {}
2. 方法不是 public
Spring AOP 代理只能拦截 public 方法。
3. 同类内部调用
java
this.sendEmail(); // 无效
必须通过 Spring 注入调用。
4. 默认线程池不可控
如果不自定义线程池:
- 线程名混乱
- 并发不可控
- 容易打爆 CPU
5. 异常被吞掉
异步方法抛出的异常不会自动显示,需要日志或回调处理。
一句话总结:
@Async 不是魔法,本质是 AOP + 线程池。
第二部分:线程池参数怎么调?
线程池不是"越大越好"。
四个核心参数
| 参数 | 含义 |
|---|---|
| coreSize | 常驻线程 |
| maxSize | 最大线程 |
| queueCapacity | 排队容量 |
| keepAlive | 回收时间 |
通用经验值
CPU 密集型
java
core = CPU 核心数 + 1
IO 密集型
java
core = CPU × 2 ~ 3
拒绝策略选择
推荐:
java
CallerRunsPolicy
含义:线程池满时让调用方执行,形成削峰。
线程池调优思维
不是凭感觉,而是:
- 压测
- 观察 CPU
- 观察队列堆积
- 微调参数
一句话总结:
线程池调优 = 压测 + 观察 + 调整。
第三部分:线程池 vs MQ 怎么选?
很多人会把两者混为一谈。
线程池的定位
适合:
- 单服务内部并发
- 写日志
- 发邮件
- 图片压缩
关键词:提速
MQ 的定位
适合:
- 高并发注册
- 秒杀
- 订单系统
- 削峰解耦
关键词:稳
注册场景拆解
同步主链路:
- 参数校验
- 唯一性校验
- 写用户表
异步旁路:
- 发短信
- 发邮件
- 发券
- 写日志
一句话记忆:
线程池解决"快",MQ 解决"稳"。
最终总结
后端并发不是:
多开线程
而是:
合理调度资源 + 正确选型。
- @Async 解决"用"
- 线程池解决"稳"
- MQ 解决"系统级并发"
真正的后端工程能力,不在于 API 熟练度,
而在于:
知道什么时候用什么工具。