🎯 Java并发 · 后端架构

🔥 虚拟线程不是"免费的午餐",pinning、ThreadLocal 膨胀和下游资源打满三大坑,让一堆团队在 JDK21 到 JDK25 之间悄悄又把线程池捡了回来。

一、炒作之后,是现实泼的一盆冷水

JEP 444 在 Java 21 落地时,全网都在喊"并发编程革命""线程池调优时代终结了"。可三年过去,JDK 一路推进到 25,虚拟线程却并没有如预期那样席卷生产环境,很多团队嘴上说着拥抱 Loom,手上还死死抱着 ThreadPoolTaskExecutor 那套老线程池。原因说穿了就一个字:坑。虚拟线程的优势区间非常窄——只在"以 I/O 等待为主的高并发"场景里才立竿见影,一旦踩进它不擅长的地带,性能不升反降,还极难排查。

知乎上有团队晒出真实经历:JDK21 跑半年后,P99 延迟不降反升、线程池莫名卡死,最后在 2026 年 3 月亲手把两个核心服务的虚拟线程换回了平台线程。这种"全面拥抱→部分撤退"的曲线,比任何技术博客都更有说服力。

二、三大坑,个个都要命

头号事故是 pinning(钉住)。JDK21 里,虚拟线程一旦进入 synchronized 块或 native 方法就无法从载体线程卸载,载体池被耗尽后,整个进程"活着却不再干活",Netflix 在 2024 年 7 月就把这个事故写成了经典案例。直到 JEP 491 在 JDK24 才修掉了 synchronized 引发的 pinning,但 native 方法和文件 I/O 的 pinning 依然存在。第二坑是 ThreadLocal 膨胀——虚拟线程不复用,原来 200 个线程的 ThreadLocal 变成"每请求一个实例",堆内存被悄悄掏空。第三坑最隐蔽:瓶颈没消失,只是往下游转移了。

虚拟线程把 Tomcat 的并发上限拆掉之后,压力全都砸向数据库连接池、文件描述符和下游 API 的限流,下一个告警几乎总是来自下游被打满。更别提 Prometheus 里 thread.name 标签在百万级虚拟线程下引发的指标基数爆炸,以及 Arthas 里根本看不到虚拟线程的排障噩梦。

三、抱线程池,其实是一种理性

所以别再嘲讽"还在用老一套"的人了——他们可能只是被坑过。对于计算密集型任务、CPU 绑定场景,虚拟线程不仅没收益,反而因为调度开销拖后腿。真正稳妥的姿势,是按工作负载分类:I/O 密集用虚拟线程配 Semaphore 限流,计算密集继续用固定线程池,两者各归其位。JDK25 作为首个纳入 JEP491 和 Scoped Values 的 LTS,才是谨慎团队真正该出手的升级目标。

综合 InfoQ、掘金、javacodegeeks 等社区实测报道 | 2026-08-24