1. 准备工作
依赖注入
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- TransmittableThreadLocal (TTL) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.14.2</version>
</dependency>
</dependencies>
定义线程池
@EnableAsync
@Configuration
public class CustomAsyncAutoConfiguration{
@Bean("virtualThreadExecutor")
public TaskExecutor virtualThreadExecutor() {
ThreadFactory virtualThreadFactory = Thread.ofVirtual()
.name("my-virtualThreadExecutor", 0) // 前缀 + 起始编号
.factory();
return new TaskExecutorAdapter(Executors.newThreadPerTaskExecutor(virtualThreadFactory));
}
// 传统线程池执行器
@Bean("threadPoolTaskExecutor")
public TaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("Async-Pool-threadPoolTaskExecutor");
executor.initialize();
return executor;
}
}
定义上下文
public class TestContextHolder {
private static final ThreadLocal<String> TEST = new ThreadLocal<>();
public static void set(String value){
TEST.set(value);
}
public static String get(){
return TEST.get();
}
}
controller
@RestController
public class TestController {
@Autowired
private AsyncService asyncService;
@GetMapping("/test-io-task")
public String testIoTask() {
TestContextHolder.set("虚拟线程上下文");
asyncService.doIoBoundTask(); // 使用虚拟线程
return "IO任务已提交(虚拟线程)";
}
@GetMapping("/test-cpu-task")
public String testCpuTask() {
TestContextHolder.set("传统线程池上下文");
asyncService.doCpuBoundTask(); // 使用传统线程池
return "CPU任务已提交(线程池)";
}
@GetMapping("/test-cpu-task1")
public String testCpuTask1() {
TestContextHolder.set("默认线程池上下文");
asyncService.doCpuBoundTask1(); // 使用默认线程池
return "CPU任务已提交(线程池)";
}
}
service
@Service
public class AsyncService {
// 使用虚拟线程执行(适合IO密集型任务)
@Async("virtualThreadExecutor")
public void doIoBoundTask() {
System.out.println("IO任务运行在: " + Thread.currentThread()+":"+TestContextHolder.get());
}
// 使用传统线程池执行(适合CPU密集型任务)
@Async("threadPoolTaskExecutor")
public void doCpuBoundTask() {
System.out.println("CPU任务运行在: " + Thread.currentThread()+":"+TestContextHolder.get());
}
@Async
public void doCpuBoundTask1() {
System.out.println("默认线程池的CPU任务运行在: " + Thread.currentThread()+":"+TestContextHolder.get());
}
}
测试结果
CPU任务运行在: Thread[#79,Async-Pool-threadPoolTaskExecutor1,5,main]:null
IO任务运行在: VirtualThread[#80,my-virtualThreadExecutor0]/runnable@ForkJoinPool-1-worker-1:null
默认线程池的CPU任务运行在: Thread[#83,SimpleAsyncTaskExecutor-1,5,main]:null
看结果可知TestContextHolder.get()获取的值为null、说明ThreadLocal类不支持上下文传递
我们现在更改TestContextHolder类的ThreadLocal的实现类为TransmittableThreadLocal
private static final ThreadLocal<String> TEST = new TransmittableThreadLocal<>();
再次执行测试 结果为:
默认线程池的CPU任务运行在: Thread[#81,SimpleAsyncTaskExecutor-1,5,main]:默认线程池 传统线程池上下文
IO任务运行在: VirtualThread[#82,my-virtualThreadExecutor0]/runnable@ForkJoinPool-1-worker-1:虚拟线程上下文
CPU任务运行在: Thread[#85,Async-Pool-threadPoolTaskExecutor1,5,main]:传统线程池上下文