Spring Boot 自动配置之 TaskExecutor

TaskExecutor 是什么?

Spring 的 TaskExecutor 本质上是对 Java Executor 的抽象封装,用来异步执行任务,把任务提交到线程池里运行,而不是阻塞当前线程。

主要作用:解耦任务提交与执行,提升并发能力和系统吞吐量。

常见场景:

  • 异步方法执行(配合 @Async 使用)。
  • 并发处理耗时任务(如批量数据处理、文件上传、消息发送)。
  • 后台任务执行(日志写入、通知推送、邮件发送)。

一句话理解:TaskExecutor 就是 Spring 提供的"线程池接口",常用于异步化和并发任务处理。

Spring Boot 自动配置类

所在包:org.springframework.boot.autoconfigure.task

类名:TaskExecutionAutoConfiguration

java 复制代码
@ConditionalOnClass(ThreadPoolTaskExecutor.class)
@AutoConfiguration
@EnableConfigurationProperties(TaskExecutionProperties.class)
@Import({ TaskExecutorConfigurations.ThreadPoolTaskExecutorBuilderConfiguration.class,
		TaskExecutorConfigurations.SimpleAsyncTaskExecutorBuilderConfiguration.class,
		TaskExecutorConfigurations.TaskExecutorConfiguration.class,
		TaskExecutorConfigurations.BootstrapExecutorConfiguration.class })
public class TaskExecutionAutoConfiguration {

	/**
	 * Bean name of the application {@link TaskExecutor}.
	 */
	public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";

}

具体的自动配置类是由 TaskExecutorConfiguration 类来完成的。TaskExecutor 被自动配置后生成的 Bean 的名称是 "applicationTaskExecutor"

通过 @EnableAsync 注解来启用 @Async 注解

注解:@EnableAsync

java 复制代码
@Service
@EnableAsync
public class DemoService {

}

@EnableAsync 注解,可以在 @Component 、@Service、@Configuration 标注的类上使用。

使用自动配置的 TaskExecutor

具体的自动配置的类:org.springframework.boot.autoconfigure.task.TaskExecutorConfiguration

自动配置的 bean 代码如下:

java 复制代码
	@Configuration(proxyBeanMethods = false)
	@Conditional(OnExecutorCondition.class)
	@Import(AsyncConfigurerConfiguration.class)
	static class TaskExecutorConfiguration {

		@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)
		@ConditionalOnThreading(Threading.VIRTUAL)
		SimpleAsyncTaskExecutor applicationTaskExecutorVirtualThreads(SimpleAsyncTaskExecutorBuilder builder) {
			return builder.build();
		}

		@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)
		@Lazy
		@ConditionalOnThreading(Threading.PLATFORM)
		ThreadPoolTaskExecutor applicationTaskExecutor(ThreadPoolTaskExecutorBuilder threadPoolTaskExecutorBuilder) {
			return threadPoolTaskExecutorBuilder.build();
		}

	}

从以上代码可以看出自动配置的Bean 的名称是 "applicationTaskExecutor", 具体类型因使用的线程类型而不同。

java 复制代码
package com.example.demo.service;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;

@Service
@EnableAsync
public class DemoService {

    /**
     * 异步执行的任务方法,无返回值
     * 该方法会在后台线程中执行,模拟耗时操作(休眠10秒)
     * 使用@Async注解标记为异步方法
     */
    @Async
    public void asyncTask() {
        try {
            // 模拟耗时操作,线程休眠10秒
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // 恢复中断状态,保持线程的中断标志
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 异步执行的任务方法,带有返回值
     * 该方法会在后台线程中执行,模拟耗时操作(休眠10秒),然后返回结果
     * 使用@Async注解标记为异步方法
     *
     * @return Future<String> 异步执行结果的Future对象,包含返回字符串"Hello, World!"
     */
    @Async
    public Future<String> asyncTaskWithReturnValue() {
        try {
            // 模拟耗时操作,线程休眠10秒
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // 恢复中断状态,保持线程的中断标志
            Thread.currentThread().interrupt();
        }
        // 返回异步执行结果
        return CompletableFuture.completedFuture("Hello, World!");
    }

}
java 复制代码
    @Autowired
    private TaskExecutor applicationTaskExecutor;

    @RequestMapping("/task")
    public Response task() {
        applicationTaskExecutor.execute(() -> {
            System.out.println("task execute");
        });
        return Response.buildSuccess();
    }

    @RequestMapping("/asyncTask")
    public Response demo() throws ExecutionException, InterruptedException {
        Future<String> stringFuture = demoService.asyncTaskWithReturnValue();
        String s = stringFuture.get();
        return SingleResponse.of(s);
    }

使用 Spring Boot 自动配置的 TaskExecutor,通常有两种方式:

1、通过 @Autowired 注入 Bean;

2、使用 @Async 注解,注意:此注解必须用在 非 @Configuration标注的类里面的方法上。

TaskExecutor 使用的线程池默认配置

TaskExecutor 背后使用的线程池为 ThreadPoolTaskExecutor,默认参数如下:

  1. corePoolSize 核心线程数为 8
  2. 如果指定的队列长度 > 0 则使用 LinkedBlockingQueue (有界阻塞队列),否则为 SynchronousQueue(同步队列);
  3. queueCapacity 队列长度默认为 Integer.MAX_VALUE,无界的;
  4. maxPoolSize 最大线程数默认为 Integer.MAX_VALUE;
  5. allowCoreThreadTimeOut 默认为 true,这意味着运行核心线程被回收;
  6. keepAlive 空闲时间默认为 1 分钟;
  7. awaitTermination ,默认 false;
  8. threadNamePrefix,线程名称前缀,默认 "task-"。

以上默认配置如果直接在生产上使用是有很大风险的,比如:内存溢出,部分参数默认值是不合理的,比如:queueCapacity 、maxPoolSize、allowCoreThreadTimeOut****等,可以通过 application.yml 配置文件来更改这些默认配置,比如:

XML 复制代码
spring:
  task:
    execution:
      pool:
        core-size: 5          # 核心线程数
        max-size: 10          # 最大线程数
        queue-capacity: 100   # 队列容量
        keep-alive: 60s       # 非核心线程存活时间
      thread-name-prefix: async-exec-   # 线程名前缀
      shutdown:
        await-termination: true         # 应用关闭时是否等待任务完成
        await-termination-period: 30s   # 最长等待时间

或通过实现 ThreadPoolTaskExecutorCustomizer 接口来自定义配置参数,

java 复制代码
import org.springframework.boot.task.ThreadPoolTaskExecutorCustomizer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

@Component
public class TaskExecutorCustomizer implements ThreadPoolTaskExecutorCustomizer {

    @Override
    public void customize(ThreadPoolTaskExecutor taskExecutor) {
        taskExecutor.setCorePoolSize(5);
        taskExecutor.setMaxPoolSize(10);
        taskExecutor.setQueueCapacity(100);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("async-exec-");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(30);
    }

}

注:Spring Boot 版本为 3.5.5

相关推荐
爱读源码的大都督2 小时前
Spring AI Alibaba JManus底层实现剖析
java·人工智能·后端
间彧2 小时前
ReentrantLock与ReadWriteLock在性能和使用场景上有什么区别?
java
Lbwnb丶2 小时前
p6spy 打印完整sql
java·数据库·sql
间彧2 小时前
公平锁与非公平锁的选择策略与场景分析
java
渣哥2 小时前
锁升级到底能不能“退烧”?synchronized 释放后状态解析
java
间彧3 小时前
Java ReentrantLock详解与应用实战
java
间彧3 小时前
volatile与Atomic类的性能对比与适用场景分析
java
间彧3 小时前
Java Atomic类详解与实战应用
java
间彧3 小时前
Java 中volatile详解与应用
java