JDK 21+虚拟线程支持同步写法实现百万级并发,需用newVirtualThreadPerTaskExecutor()而非传统线程池,配合适配库可自动挂起I/O阻塞,避免CPU密集任务,栈与ThreadLocal更轻量,载体线程默认足够。

不用重构业务逻辑,也不用学响应式编程,JDK 21+ 的虚拟线程让你用最熟悉的同步写法,就能撑住百万级并发连接。
选对执行器:直接用 newVirtualThreadPerTaskExecutor()
虚拟线程不是用来“塞进”传统线程池的——那是常见误用,反而拖慢性能。它需要专属调度环境。
- ✅ 正确做法:用 Executors.newVirtualThreadPerTaskExecutor(),它返回的 ExecutorService 内部自动绑定 ForkJoinPool.commonPool() 作为载体调度器
- ✅ Spring Boot 3.2+ 可替换 Web 容器线程模型,例如 Tomcat:
在配置类中定义 Bean,把 HTTP 请求直接交给虚拟线程执行 - ❌ 错误写法:用
newFixedThreadPool(200)或newCachedThreadPool()包裹虚拟线程任务,等于白建,还增加调度开销
写同步代码,但获得异步吞吐
HTTP 调用、数据库查询、文件读写、甚至 Thread.sleep(),照常写阻塞式逻辑。JVM 在 I/O 阻塞点(如 socket.read、JDBC 查询、锁等待)自动挂起虚拟线程,腾出载体线程跑别的任务。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 确保底层库支持挂起语义:JDK 自带
HttpClient、Spring WebClient 6.1+、PostgreSQL JDBC 42.7+、HikariCP 5.0+ 等已适配 - 一个典型场景:单请求串行调用 3 个下游接口,每个平均耗时 200ms,传统 200 线程池最多并发 200;换成虚拟线程后,单机轻松维持 10 万+ 并发连接,QPS 显著提升
- 避免在虚拟线程里做纯 CPU 密集型长任务(比如大数组排序、RSA 加密),否则会卡住载体线程;真有需要,应显式提交到
ForkJoinPool.commonPool()之外的专用 CPU 线程池
变量与上下文管理更轻量
高并发下变量本身不构成瓶颈,真正影响伸缩性的是执行上下文与线程生命周期的耦合。虚拟线程对此做了关键优化:
立即学习“Java免费学习笔记(深入)”;
- 栈帧按需分配:初始仅几百字节堆内存,以 StackChunk 形式动态切片增长,避免平台线程默认 1MB 固定栈的浪费
-
ThreadLocal仍可用,但语义更轻:值随虚拟线程创建/销毁自动清理,无需手动 remove,也不建议跨任务长期持有 - 虚拟线程栈不参与 GC Roots 扫描,大量临时对象不会拖慢垃圾回收,间接保障变量操作稳定性
调优载体线程池:多数情况无需干预
虚拟线程默认复用 ForkJoinPool.commonPool(),并行度等于 CPU 核心数。这对绝大多数 I/O 密集型服务完全够用。
- 压测时若发现 CPU 利用率偏低、吞吐却上不去,才说明载体线程成了瓶颈——此时可考虑自定义 ForkJoinPool 并调整
parallelism - 注意:不要盲目增大并行度。载体线程过多反而引发竞争,通常保持为 CPU 核心数或略高(如 ×1.2)即可
- 不需要设置拒绝策略、队列容量或线程存活时间——虚拟线程即用即毁,无资源竞争压力

















