核心思路是不改业务逻辑,仅将查库、发消息等耗时操作从主线程移至定制化线程池并行执行,主线程立即返回;重点改造定时任务监控推送、用户请求旁路操作及外部系统调用三类阻塞场景;须手写threadpoolexecutor,按场景配置队列、拒绝策略与线程参数,并通过单例asynctaskexecutor统一管控生命周期与埋点。

核心思路很明确:不改业务逻辑,只换执行容器。把原来在主线程里串行跑的耗时操作(比如查库、发消息、调第三方接口),挪到线程池里并行跑,主线程立即返回,不再卡住。
识别哪些同步点必须改
重点盯三类典型阻塞场景:
- 定时任务中不断膨胀的监控推送——像每5分钟一次、越推越慢的数据库写入
- 用户请求链路中非核心但耗时的旁路操作——例如下单后异步发短信、记录行为日志、触发风控快照
- 外部系统调用——HTTP请求、MQ发送、文件上传等I/O密集型动作
这些操作本身不影响主流程正确性,但拖慢响应、堆积线程、压垮连接池。改异步不是为了“炫技”,而是解耦责任、守住主干SLA。
选对线程池类型和参数
别直接用 Executors.newFixedThreadPool() 这类快捷工厂——它们隐藏了关键配置,线上容易出问题。推荐手写 ThreadPoolExecutor,并按场景设参:
- 监控/日志类后台任务:用 SynchronousQueue + CallerRunsPolicy,拒绝策略直接在调用线程执行,防止任务无限堆积
- 高并发旁路调用(如短信):设合理 corePoolSize(比如4–8)、maxPoolSize(16–32),队列用 LinkedBlockingQueue(容量可控,避免OOM)
- 强调响应优先的场景:考虑 keepAliveTime 设短(3–5秒),空闲线程快速回收,节省资源
务必配命名线程工厂(NamedThreadFactory),方便JVM线程dump时一眼识别来源。
封装执行入口,统一管控生命周期
避免散落 executor.submit(),建一个单例管理器,比如 AsyncTaskExecutor:
- 内部持有一个或多个定制化线程池(按任务类型隔离,防互相干扰)
- 提供 execute(Runnable) 和 submit(Callable
) 两个轻量方法 - 实现 Disposable 接口,在Spring容器关闭前调用 shutdownNow(),避免应用停机卡住
- 加简单埋点:记录提交数、拒绝数、平均排队时长,用于后续容量评估
结果处理要克制,别为异步而异步
大部分重构目标是“发出去就完事”,不需要等结果:
- 用 execute() 提交 Runnable 即可,无返回、无异常透出
- 真需要结果且不能丢——比如异步校验后要更新状态,才用 submit() + Future.get(timeout, unit),并配超时和异常兜底
- 完全避开 CompletableFuture.join() 或 get() 在Web请求线程中调用,否则又变回同步阻塞
异步的本质是“接受延迟可见性”,而不是“假装没发生”。该记日志记日志,该落库落库,只是不做实时依赖。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











