配置 @Async 时,先确认 Spring Boot 版本和实际选中的执行器。线程池默认值属于具体版本的实现,不能把“8 个核心线程、最大线程数无限大”当成所有 Boot 项目的固定行为。

默认值为什么容易被误读

以下仅以 Spring Boot 2.7.18 的 TaskExecutionProperties 为例:

属性该版本默认值
pool.core-size8
pool.max-sizeInteger.MAX_VALUE
pool.queue-capacityInteger.MAX_VALUE
pool.keep-alive60 秒
pool.allow-core-thread-timeouttrue
thread-name-prefixtask-

无界队列下,任务通常先排队,max-size 不能按想象无限扩充线程。风险可能表现为积压和等待变长,不能仅凭默认最大值断言会立刻创建大量线程。2.7.18 属性源码

配置 Boot 自动提供的执行器

下面容量只是示例,需要按任务耗时、内存和下游并发能力调整:

spring:
  task:
    execution:
      thread-name-prefix: business-
      pool:
        core-size: 4
        max-size: 8
        queue-capacity: 100
        keep-alive: 60s

thread-name-prefix 位于 execution 下,与 pool 同级。这里没有通用的 spring.task.execution.enabled 开关;异步方法处理还需要 @EnableAsync,且自定义 Executor 等条件会影响 Boot 自动配置是否生效。

明确指定一个业务执行器

若项目有多个池,直接用名字绑定更清楚。以下是 Spring 5.x 的配置类:

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean("businessExecutor")
    public Executor businessExecutor() {
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        pool.setCorePoolSize(4);
        pool.setMaxPoolSize(8);
        pool.setQueueCapacity(100);
        pool.setThreadNamePrefix("business-");
        pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        return pool;
    }
}

将 @Async(“businessExecutor”) 标在 Spring 管理的服务方法上,通过注入的代理对象调用。由容器管理的 ThreadPoolTaskExecutor 会参与 Bean 生命周期;不要为了运行示例在每个请求里新建线程池。

@Async 默认依赖代理,同一个对象内部直接调用自身方法不会自动变成异步。void 方法异常与 Future/CompletableFuture 异常的观察方式也不同;任务提交被拒绝时还要明确业务如何反馈,不能把“调用立即返回”当作执行成功。Boot 任务执行说明

如何确认配置真的生效

先在开发环境确认调用线程与执行线程名称,再观察池大小、队列和拒绝次数。若名称仍不是预期值,检查 Bean 名称、@Async 指定值以及是否发生自调用。容量测试应同时观察下游承载能力,增加线程数并不必然增加吞吐。