资讯动态

Java虚拟线程(四)

发布时间:2026/10/2 7:15:26 来源:尧图企业网站定制
SpringBoot3.2 全局开启虚拟线程后业务代码使用虚拟线程处理业务前置spring.threads.virtual.enabledtrue这个配置只作用于 Web 容器Tomcat/JettyHTTP 请求进来由虚拟线程处理 Controller。⚠️重要它不会自动把你业务里异步任务变成虚拟线程全局开启只是 Web 请求线程是 VT你自己代码里手动Async、线程池默认仍然是平台线程需要单独处理。两种场景分开1. 同步业务逻辑Controller 里直接写请求本身跑在虚拟线程上业务代码天然就在虚拟线程执行无需额外编码。RestController public class OrderController { GetMapping(/order/get) public String getOrder() { // 当前线程就是虚拟线程 Thread t Thread.currentThread(); System.out.println(isVirtual: t.isVirtual()); // DB查询、RPC调用直接写跑在Web虚拟线程 orderService.query(); remoteService.call(); return success; } }✅ 特点不需要创建任何 Executor整个请求链路都在虚拟线程。注意Controller 内同步调用属于 Web VT 的主线程IO 阻塞会释放载体线程享受虚拟线程优势。2. 业务异步任务需要新开线程执行如 Async、后台任务全局开启 Web 虚拟线程不会改造 Async 默认线程池。SpringAsync默认使用SimpleAsyncTaskExecutor平台线程想要异步任务也使用虚拟线程需要手动替换Async的执行器。方式 A全局替换 Async 执行器为虚拟线程执行器推荐import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; Configuration EnableAsync public class AsyncVtConfig { /** * 虚拟线程执行器用于Async */ Bean public TaskExecutor taskExecutor() { ExecutorService vtExecutor Executors.newVirtualThreadPerTaskExecutor(); return new org.springframework.scheduling.concurrent.ConcurrentTaskExecutor(vtExecutor); } }使用Service public class BizService { Async public void asyncHandleBiz() { // 这个方法运行在全新虚拟线程 System.out.println(Thread.currentThread().isVirtual()); } }调用// 在ControllerWeb虚拟线程中调用 bizService.asyncHandleBiz();注意newVirtualThreadPerTaskExecutor不是线程池每次提交新建虚拟线程用完销毁。方式 B单独注入 Executor手动提交任务细粒度控制Bean public ExecutorService businessVtExecutor() { return Executors.newVirtualThreadPerTaskExecutor(); }业务代码Service public class BizService { Autowired private ExecutorService businessVtExecutor; public void submitTask() { businessVtExecutor.submit(() - { // 任务运行在虚拟线程 System.out.println(Thread.currentThread().isVirtual()); }); } }✅ 最佳实践全局 VT 环境下1. 优先复用 Web 请求虚拟线程同步优先把业务逻辑写在 Controller 同步链路。优点不需要额外创建虚拟线程链路追踪、MDC 天然连贯。适用大部分 HTTP 接口串行 DB/RPC 调用。2. 并行调用场景在当前 Web 虚拟线程内开启多个虚拟线程并行在 Controller当前是 VT中使用Executors.newVirtualThreadPerTaskExecutor()并行发起多个 IO 调用。GetMapping(/order/detail) public Object getOrderDetail() throws ExecutionException, InterruptedException { try (var executor Executors.newVirtualThreadPerTaskExecutor()) { var future1 executor.submit(() - userService.getUser()); var future2 executor.submit(() - goodsService.getGoods()); return Map.of(user, future1.get(), goods, future2.get()); } }try-with-resourcesExecutorService 会自动 close等待所有虚拟线程任务完成。非常适合接口内并行调用多个 RPC/DB。⚠️ 重点坑高频踩坑1. 全局 spring.threads.virtual.enabledtrue ≠ Async 自动变成虚拟线程很多人踩这个坑Web 线程是 VT但异步任务还是平台线程。必须手动替换 Async 的 TaskExecutor。2. 不要池化虚拟线程❌ 错误写法// 错误毫无意义废掉虚拟线程能力 ExecutorService pool Executors.newFixedThreadPool(10, Thread.ofVirtual().factory());3. 并行 IO 场景必须加 Semaphore 限流哪怕是虚拟线程并行大量 RPC一定要加前面 AOP 封装的VtSemaphoreLimit防止瞬间大量 VT 打爆下游。GetMapping(/batch) public void batch() { try (var executor Executors.newVirtualThreadPerTaskExecutor()) { for(int i0;i1000;i){ executor.submit(() - { remoteService.callRpc(); // 这里方法带VtSemaphoreLimit做并发控制 }); } } }4.synchronized块内长时间 IO 阻塞会卡住载体线程 同步锁内不要放 RPC/DB 查询优先 ReentrantLock。5.MDC / 链路追踪问题Controller 主线程Web VTMDC 正常。新开虚拟线程MDC 不会自动传递需要手动拷贝 traceId。解决方案提交任务时手动把 MDC 上下文传入或者使用包装 Runnable。MDC 传递简易包装示例public static Runnable wrapWithMdc(Runnable task) { MapString, String contextMap MDC.getCopyOfContextMap(); return () - { if (contextMap ! null) { MDC.setContextMap(contextMap); } try { task.run(); } finally { MDC.clear(); } }; } // 使用 executor.submit(wrapWithMdc(() - remoteService.callRpc()));6. 调度任务 ScheduledScheduled默认使用平台线程池。如果想定时任务跑虚拟线程自定义TaskScheduler使用虚拟线程执行器。快速选型总结Controller 同步业务直接写天然跑在 Web 虚拟线程无需额外代码Controller 内并行多个 IO 请求try(newVirtualThreadPerTaskExecutor())并行提交方法异步解耦Async全局替换 TaskExecutor 为虚拟线程执行器后台独立任务注入newVirtualThreadPerTaskExecutor手动 submit总结spring.threads.virtual.enabledtrue只把 Tomcat 的 HTTP 处理线程改成虚拟线程不会自动改造业务异步任务。Controller 同步业务天然跑在虚拟线程并行 IO 可以在接口内创建虚拟线程执行器Async 需要手动替换 TaskExecutor新开虚拟线程要手动传递 MDC并且使用 Semaphore 限制下游并发。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑