Zademy

JDK 25 LTS:爆炸性性能、极致生产力和重复代码的终结

Java
Java; JDK25
words 字

Java 25 是 LTS 版本。Oracle 承诺至少 8 年延长支持,所以这不是试水版,是可以直接押注的。

我最近把几个项目迁了过来,下面说说实际体验。

性能:不改代码就变快

SPECjbb2015 基准测试的数据很直白。从 JDK 21 迁到 25,关键延迟(Critical JOPS)降了约 10%,最大吞吐量(Max JOPS)涨了约 5%。云成本通常能省 20-30%,因为 CPU 和内存吃得少了。

如果你还停在 Java 8,跳跃更夸张。延迟性能翻倍不止,云资源能砍掉三分之一。

紧凑对象头(JEP 519)

这个功能正式转正了。64 位架构上,HotSpot 的对象头从 96/128 位砍到 64 位。实际效果:堆内存用量降了最多 22%,小对象体积缩了 20%。

对象变小了,CPU 的 L1、L2、L3 缓存能塞进更多东西,执行自然就快。这不是玄学,是缓存命中率的物理规律。

AOT 方法分析(JEP 515)

JVM 启动和预热时间有明显改善。HotSpot 现在能复用上次运行收集到的方法 profile,JIT 编译器一启动就拿出最优的本机代码,不用再慢慢热身。对于 Serverless 和短生命周期进程,这个改进体感很强。

JFR 改进

JDK 25 的 Java Flight Recorder 升级了几块:Linux 上的 CPU Time Profiling 更精确了,协作采样做了改进,方法计时和 tracing 也更细了。做性能调优的时候这些数据更靠谱。

写得更少

Java 25 加了几个我等了很久的语言特性。

极简 main(JEP 512)——写 main 方法不用再声明 class 和 package。写个快速脚本终于不痛苦了,Java 不再用仪式感把人挡在门外。

Switch 模式匹配做了增强,case 里能直接解构 record,逗号分隔的多模式也支持了。代码短了,可读性上去了。

匿名模式 _——用下划线忽略 record 组件或不需要的变量。终于不用为了一个用不到的变量绞尽脑汁取名。

模块导入(JEP 511)——import module java.base; 一行搞定,不用再写一堆 import java.util.List。

另外,instanceof 和 switch 中使用原始类型的模式匹配进入了第三次预览(JEP 507),语言一致性越来越好。

并发:Scoped Values 接替 ThreadLocal

Scoped Values(JEP 506)

这是 ThreadLocal 的现代替代品,专门为 Virtual Threads 设计。

最大的区别:值一旦定义就不可变,没有副作用。作用域也有限——值只存在于 ScopedValue.where(…).run(…) 的执行块内,退出自动消失,不会内存泄漏。

说实话,Virtual Threads 在数据库密集型场景下并不总能提速(连接池瓶颈还在),但它最大的价值是开发体验。可以扔掉响应式编程那套复杂的东西,回到简单的 Thread-per-Request 模型。

结构化并发(JEP 505,第五次预览)

这个 API 把不同线程里的关联任务当作一个工作单元来管。错误传播、取消操作、可观察性,都比裸写 ExecutorService 清晰得多。

JSpecify:向 NPE 宣战

严格来说不是 JEP,但 Spring Framework 7 采纳了 JSpecify——nullability 的开放标准——这件事值得说。IDE 和静态分析器终于能统一理解一个值能不能为 null。运行时的 NullPointerException,离我们又远了一步。

其他改进

编译器、JVM 运行时和垃圾收集器都有常规优化,JIT 生成更高效的代码,GC 暂停进一步缩短。JDK 标准库也有一批功能性更新。这些不单独展开,但整体体感是:同一个应用,跑得更稳了。

迁移之前要注意的

三件事提前知道。

LTS 支持方面,Java 25 有 8 年窗口,不用频繁大版本迁移。

x86 32 位支持被砍了。如果你的系统还有 32 位的,先升级。

Security Manager 彻底禁用,API 未来版本会删除。还在用的赶紧迁移到模块系统或容器安全方案。

我的判断

JDK 25 是一个值得迁的版本。堆内存实打实地降了,启动快了,样板代码少了。还在 Java 8 或 11 的,这个版本的差距大到没有理由不动。