Java 最新 LTS 为 25。本文讲清虚拟线程解决的真实问题(I/O 密集而非 CPU 密集)、分代 ZGC 的适用场景,并给出不同现状下的升级决策表与四步落地姿势。
Java 已经走到 LTS 版本 25,特性版本推进到 26(数据来源:Eclipse Temurin 官方发布接口)。对大量仍停留在 Java 8 或 Java 11 的后端团队来说,摆在面前的问题是:现在该不该升?升到哪?虚拟线程和分代 ZGC 值不值得为它们重构?
本文不做版本特性罗列,只回答工程决策:什么情况下升级收益立竿见影,什么情况下升级只是自找麻烦。
一、版本坐标:先分清 LTS 与特性版
当前 Java 的 LTS 序列为 8、11、17、21、25,最新 LTS 为 25,最新特性版本为 26。企业生产环境应当只考虑 LTS——特性版本只有半年支持周期,适合尝鲜而非部署。
这意味着实际可选的落点只有三个:17(保守)、21(主流)、25(激进)。仍在 8 或 11 的团队,跳过中间版本直接评估 21 或 25 往往是更省事的路径。
二、虚拟线程:它解决的是并发模型问题,不是性能银弹

虚拟线程(Virtual Threads)由 JDK 21 正式引入,核心价值是:让”一个请求一个线程”的同步阻塞写法,重新变得可接受。
过去为了扛住高并发,我们不得不把代码改写成响应式风格(CompletableFuture、Reactor、RxJava),代价是可读性、调试难度和栈信息的全面恶化。虚拟线程让你可以继续写同步代码,同时拥有接近异步框架的吞吐量。
// 虚拟线程下,这样的阻塞写法不再需要改造成响应式
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i ->
executor.submit(() -> {
var resp = httpClient.send(request, BodyHandlers.ofString());
return save(resp.body());
})
);
}
三个必须知道的边界
- 它加速的是”等待”,不是”计算”。 阻塞在 I/O 上的任务能获益巨大;纯 CPU 密集任务没有任何提升,甚至因为调度开销略有回退;
- 小心 pinned(钉住)问题。 在
synchronized块或 native 调用中阻塞时,虚拟线程无法从载体线程上卸载,吞吐量会打回原形。改造时用 JFR 观察jdk.VirtualThreadPinned事件定位; - 池化习惯要改。 虚拟线程极其廉价,不该被池化。沿用了线程池限流的代码需要重新审视——限流应该交给信号量或网关,而不是靠线程数量。
三、分代 ZGC:低延迟场景的分水岭
ZGC 引入分代(Generational)后,在保持极低停顿的同时显著改善了吞吐与内存放大问题。它适合的场景非常明确:大堆内存 + 对尾延迟敏感的服务,例如实时定价、风控决策、在线推荐。
如果你的服务堆内存只有 2–4GB、且能接受几十毫秒的 GC 停顿,G1 依然是更稳妥、更省心的选择。ZGC 不是”更好”,是”更适合特定场景”。
四、升级决策表
五、升级的正确姿势
- 先解耦 JDK 与框架升级。 两件事一起做,出问题无法归因。先升 JDK 跑稳,再动 Spring 等框架;
- 依赖先行。 用构建工具的依赖检查找出不支持目标版本的库,尤其是字节码增强类(监控 agent、APM、ORM 增强);
- 压测看尾延迟,不看平均。 GC 与线程模型的收益主要体现 P99/P999,平均耗时几乎看不出差别;
- 留回滚路径。 镜像里保留旧 JDK,用启动参数切换,出问题分钟级回退。
最容易被忽略的一点:升级收益的大头往往来自”终于摆脱了八年前的依赖”,而不是某个具体特性。把升级当成一次技术债清理,收益会大得多。
六、小结
Java 25 时代,后端团队最值得关注的两件事是虚拟线程带来的并发模型回归与分代 ZGC 带来的尾延迟改善。但两者都有明确适用边界:前者只对 I/O 密集有效,后者只对大堆低延迟有效。
决策方法很简单——先量化和你相关的那个指标(吞吐量或 P99),再决定要不要动。没有度量,就没有升级的理由。
版本数据来源:Eclipse Temurin 官方发布信息接口;版本信息采集于 2026 年 9 月 1 日。虚拟线程与 ZGC 的行为以官方 JDK 文档为准。
#Java#JVM#并发编程#性能优化

