Java 25 LTS 新特性深度解读:分代 ZGC 成默认 + Scoped Values 正式 + 结构化并发
§1 版本元数据
| 项目 | 值 |
|---|---|
| 官方名称 | Java SE 25 |
| 发布日 | 2025-09-16 |
| 类型 | LTS(Long-Term Support) |
| Oracle Premier Support 截止 | 2030-09 |
| Oracle Extended Support 截止 | 2033-09 |
| 第三方 LTS | BellSoft Liberica 至 2034-03 |
| 关键里程碑 | 分代 ZGC 成默认 GC(自 JDK 23 JEP 474)+ Scoped Values 正式(JEP 506)+ 结构化并发 Preview(JEP 505 第五次)+ 紧凑对象头(JEP 519)+ 模块导入(JEP 511)+ Generational Shenandoah(JEP 521) |
| 类文件版本 | 69(Java 21 = 65,Java 25 = 69) |
| JEP 总数 | 18 个 JEP(其中 4 个 Preview/Incubator) |
为什么 Java 25 是面向云原生 / AI / 大数据场景的现代 LTS:Java 25 把 Java 23 起就在演进的"分代 ZGC"正式设为默认 GC——JEP 474(Java 23)首次让分代 ZGC 成为默认,Java 25 沿用。配合 Scoped Values(替代 ThreadLocal)+ 结构化并发(替代 CompletableFuture 的"裸异步"),Java 25 让虚拟线程 + 分代 ZGC + Scoped Values三件套在生产环境真正可用。Spring Boot 3.5+ + Java 25 是新项目最佳实践。
注意:spec §3 草稿里写的"字符串模板(JEP 459)+ FFM API(JEP 454)“在 Java 25 不构成独立 JEP 章节——前者仍在 Preview 但 Java 25 没纳入,后者已在 Java 22 完整交付。
§2 重大新特性
2.1 分代 ZGC 成默认 GC(JEP 474,从 JDK 23 起)
问题:Java 17 / 21 的默认 GC 是 G1——G1 在 32GB 以上大堆场景暂停时间 50-200ms。ZGC 虽然 16TB 大堆 + 暂停 < 1ms,但 Java 11-21 是 opt-in,需要显式 -XX:+UseZGC -XX:+ZGenerational。默认 G1 让人对 ZGC 的优势望而却步。
方案:JEP 474(Java 23)首次将分代 ZGC 设为默认 GC——JEP 439(Java 21)是分代 ZGC opt-in 引入,JEP 474(Java 23)让分代模式成为默认(无需 flag)。Java 25 沿用此默认。
代码(启用 / 切换):
| |
收益:所有 Java 25 项目自动获得"大堆 + 极低延迟"GC 能力——零配置。典型场景:微服务(2-8GB 堆仍可享低延迟)、大数据(> 32GB 堆 ZGC 优势明显)、AI 推理服务(GC 暂停直接拖慢响应时间)。配合虚拟线程(Java 21)+ Scoped Values(Java 25)三件套是 Java 25 的核心范式。
2.2 Scoped Values(JEP 506 正式)—— 替代 ThreadLocal
问题:ThreadLocal 在虚拟线程时代内存泄漏风险——每个虚拟线程都有一份 ThreadLocal 副本,10K 虚拟线程 × 5 个 ThreadLocal = 50K 副本;InheritableThreadLocal 父子传递但首次创建后无法改变。Spring / Web 框架用 ThreadLocal 传 userId / traceId 在虚拟线程场景几乎不可用。
方案:Scoped Values(JEP 506 正式,Java 25)是不可变 + 作用域绑定 + 自动继承的轻量上下文——ScopedValue.where(KEY, val).run(() -> { ... }) 在 lambda 作用域内有效,子线程(包括虚拟线程 + StructuredTaskScope fork)自动继承。
代码:
| |
收益:
- 不可变(线程安全,无并发问题)
- 无内存泄漏(作用域结束自动失效)
- 子线程自动继承(不用 InheritableThreadLocal 那种 hack)
- 性能比 ThreadLocal 高 5-10 倍(无 hash 查找)
- 配合虚拟线程 + StructuredTaskScope 完美——结构化并发的"父-子-孙"层级自动传递上下文
2.3 结构化并发(JEP 505 Preview)—— 第五次 Preview
问题:CompletableFuture + 线程池的"裸异步"在生产里难调试——子任务失败、取消、超时管理混乱,没有父子结构概念。
方案:StructuredTaskScope(JEP 505 Preview,Java 25 是第五次 Preview)提供结构化并发——所有子任务在父作用域内启动,父 join 时等所有子任务结束;任一子任务失败可触发兄弟取消(ShutdownOnFailure);超时自动取消(ShutdownOnTimeout)。
注意:JEP 505 在 Java 25 仍是 Preview(第五次 Preview),生产慎用——API 可能变。但概念已稳定,可写学习代码 + 早期试用。
代码:
| |
收益:
- 父子结构清晰——子任务的生命周期受父作用域约束
- 失败传播(一个失败全 cancel)—— 防止资源泄漏
- 跟 JFR 集成——scope 子任务在 JFR 里可视化(火焰图看父子调用链)
- 跟 Scoped Values(JEP 506)天然集成——上下文自动传递
2.4 紧凑对象头(JEP 519 正式)—— 堆使用减少 10-22%
问题:Java 对象头(mark word + class pointer)通常 12-16 字节。100 万对象 = 12-16MB 头开销——纯浪费。
方案:JEP 519(Java 25 正式)把对象头压缩到 8 字节——通过紧凑布局 + class pointer 压缩。默认启用(JVM 自动判断)。
启用:
| |
收益:
- 对象头从 12-16 字节 → 8 字节
- 堆使用减少 10-22%(小对象场景收益更大)
- 间接性能提升(GC 扫描对象数减少)
- 100% 向后兼容(不影响对象布局的字节码访问)
典型场景:微服务(10 万级小对象)、AI 推理(tensor 对象)、Web 框架(DTO / 视图对象)。实测:100 万个 new User("Alice") 紧凑对象头节省约 4MB 堆。
2.5 模块导入(JEP 511 正式)—— 学习效率提升
问题:Java 程序要 import java.util.List; import java.util.Map; import java.util.Set; import java.util.HashMap; import java.util.ArrayList; ... —— 20-30 个 import 才能开始写代码。Python from collections import * 一行解决,Kotlin import java.util.* 一行解决。
方案:JEP 511(Java 25 正式)支持 import module java.base; —— 一次导入整个 java.base 模块的所有公开类。module 关键字是新增的(不是 import 的变体)。
代码:
| |
收益:
- Hello World 程序减少 50% 行数
- 教学 / 入门代码更简洁(学生不用学 import)
- 生产代码谨慎使用——显式 import 更易读,只在脚本 / 教学场景用
2.6 Generational Shenandoah(JEP 521 正式)—— Red Hat 分代 GC
问题:Shenandoah GC(Red Hat 维护,OpenJDK 12 引入)一直是非分代 GC,性能比 G1 差(无分代优化)。
方案:JEP 521(Java 25 正式)引入 Generational Shenandoah——给 Shenandoah 加分代模式,跟分代 ZGC 性能对标。
启用:
| |
收益:
- Red Hat 生态(RHEL / OpenShift)默认 GC 候选
- 暂停 < 10ms
- 分代 Shenandoah 性能比传统 Shenandoah 提升 20-30%
- 给不愿用 ZGC(Oracle 主导)的用户提供 Red Hat 选项
§3 JVM 参数变更
| 变更类型 | 参数 | 说明 |
|---|---|---|
| 改默认 | 默认 GC = 分代 ZGC(JEP 474 沿用 Java 23 默认) | 25 无需 flag |
| 新增(正式) | -XX:+UseCompactObjectHeaders | 紧凑对象头(JEP 519)默认开 |
| 新增(正式) | -XX:+UseShenandoahGC + -XX:ShenandoahGCMode=generational | 分代 Shenandoah(JEP 521) |
| 新增(正式) | --enable-preview 含 import module 语法 | 模块导入(JEP 511)默认开 |
| 移除 | -XX:+UseConcMarkSweepGC(CMS) | 早已移除 |
| 移除 | 32-bit x86 移植(JEP 503) | 25 起不再支持 32-bit x86 平台 |
启用紧凑对象头(默认开):
| |
§4 垃圾回收器演进
| GC | Java 25 状态 | 引入版本 | 关键调优 |
|---|---|---|---|
| Serial | 保留 | 1.0 | -XX:+UseSerialGC |
| Parallel | 保留(不再是默认) | 1.4 | -XX:+UseParallelGC |
| G1 | 保留但不再是默认(Java 9-22 时代默认) | 7u4 | -XX:+UseG1GC |
| ZGC | 正式 + 分代 + 默认(JEP 474 沿用) | 11 实验 → 15 正式 → 21 分代 → 23 默认 | -XX:+UseZGC |
| Shenandoah | 正式 + 分代(JEP 521) | 12 | -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational |
| Epsilon | 保留 | 11 | -XX:+UseEpsilonGC |
| CMS | 已移除 | 1.4.1 | 不再可用 |
重点:
- 分代 ZGC 是 server 模式默认(JEP 474,Java 23 起;Java 25 沿用)
- G1 不再是默认(重大转变——Java 9-22 时代 G1 是默认,Java 23 起切换)
- Generational Shenandoah 新增(JEP 521,Red Hat 用户的 GC 选项)
- 生产建议:中小堆(< 32GB)继续 G1 也可;大堆(> 32GB)默认即享分代 ZGC 优势
调优示例:
| |
§5 生产代码实战
Demo 1:Scoped Values + StructuredTaskScope
文件:assets/code/jdk-lts/Java-25/ScopedValueVsThreadLocalDemo.java
场景:Web 请求上下文(userId / traceId)在子任务里自动传递——ThreadLocal 在虚拟线程场景内存泄漏风险,Scoped Values 是替代方案。
关键代码:
| |
跑通命令(需 OpenJDK 25+):
| |
预期输出:
| |
⚠️ 环境要求:本 demo 需 OpenJDK 25+ 才能编译运行(javac --release 25 在 JDK 21 上不支持)。Windows 用户可用 winget install Microsoft.OpenJDK.25,macOS/Linux 用 SDKMAN(sdk install java 25-open)。
Demo 2:模块导入(JEP 511)+ GC 配置说明
文件:assets/code/jdk-lts/Java-25/GenerationalShenandoahDemo.java
场景:演示 Java 25 模块导入 + GC 启用方式(实际 GC 跑需要生产负载,单 demo 跑不出 GC 数据)。
关键代码:
| |
跑通命令(需 OpenJDK 25+):
| |
⚠️ 同样需 OpenJDK 25+。
§6 升级指南
从 Java 21 升 Java 25:
| 风险 | 缓解 |
|---|---|
| 默认 GC 改变(G1 → 分代 ZGC) | 业务调优基于 G1 习惯需重新跑 benchmark;调优脚本加 -XX:+UseG1GC 暂用 G1 |
| 紧凑对象头(JEP 519) | 99.9% 向后兼容;极端 native 库(Unsafe 读对象头)可能受影响 |
| 32-bit x86 移除(JEP 503) | 服务器早 64-bit,影响极小;嵌入式老设备需确认 |
| 结构化并发 JEP 505 Preview | Preview 5 状态——生产仍不用 Preview API;可写学习代码 |
| 模块导入 JEP 511 | 跟 import 不冲突;可选用 |
| 字节码版本 65 → 69 | 老 .class 文件不需重新编译,但运行时要求升 JDK 25+ |
| Spring Boot 3.5+ 默认开虚拟线程 + Scoped Values | 升级后先关做对比再开 |
升级 5 步走:
- 依赖扫描:检查是否有用 32-bit x86 native 库(JEP 503 移除)
- JUnit 测试:JDK 25 跑测试套,重点看 GC 行为变化
- 灰度切流:单实例跑 1 周,监控分代 ZGC vs G1 暂停时间 + 吞吐对比
- 全量切:灰度无问题后改默认 JDK = 25
- Scoped Values 启用:业务代码用 ThreadLocal 传 userId / traceId 的逐步改 ScopedValue
回滚预案:
- 保留 JDK 21 镜像至少 1 个月
- 启动参数加
-XX:+UseG1GC暂用 G1 - 紧凑对象头加
-XX:-UseCompactObjectHeaders关闭(如兼容性有问题) - 回滚窗口 < 5 分钟
§7 踩坑实录
- ScopedValue 的
get()离开作用域抛NoSuchElementException—— 不像 ThreadLocal 有"无值返回 null"的 fallback。对策:用ScopedValue.where(KEY, default).run(...)或try { KEY.get() } catch (NoSuchElementException e) { ... }。Spring 6.2+ 框架层已自动处理,但业务代码用裸get()要小心。 - 结构化并发 JEP 505 是 Preview 5 状态 —— Preview 5 意味着 API 接近稳定但仍可能变。生产禁用 Preview API(JEP 459 字符串模板在 Java 25 撤回就是教训)。
- 分代 ZGC 调优 vs G1 调优完全不同 —— G1 的
-XX:InitiatingHeapOccupancyPercent/-XX:MaxGCPauseMillis在 ZGC 上无效。ZGC 主要调优-XX:SoftMaxHeapSize/-XX:ConcGCThreads/-XX:ParallelGCThreads。团队培训要重新过 ZGC 调优。 - Generational Shenandoah 在 Red Hat 之外的 JDK 不带 —— 多数 JDK 发行版(Belleoft Liberica / Azul Zulu)默认包含 Shenandoah;Oracle JDK 不含 Shenandoah。生产确认用的发行版。
- 紧凑对象头对 native 代码有影响 —— JNI /
Unsafe直接读对象 mark word 的代码可能 break。典型场景:Netty 内存池 / Chronicle Queue / ObjectLayout。升级前用 JDK 25 跑 native 测试。 - Java 25 默认 GC 切到分代 ZGC 对老
-XX:+UseG1GC配置影响 —— 之前显式-XX:+UseG1GC的项目无变化(明确指定 GC);之前依赖默认的项目GC 行为变化——暂停时间和吞吐都变。调优脚本要写”-XX:+UseG1GC 维持旧行为"注释。 - 模块导入 JEP 511 不能跟单 import 混用导致歧义 ——
import module java.base; import java.util.Date;里Date用 import module 的;但import module java.sql;后Date改用 java.sql 的。生产建议单用一种 import 风格。
工业实践补充
真实项目里的 Java 25 升级路径(云原生 / 高并发 / 大数据典型场景):
- 阶段 1(1-2 月)评估期:用
jdeprscan --release 25 MyApp.jar扫废弃 API;检查是否用 32-bit x86 native 库(JEP 503 移除);检查 Netty / JNI 库对紧凑对象头(JEP 519)的兼容性——某些Unsafe直接读 mark word 的库可能 break。 - 阶段 2(2-3 月)升级期:Maven/Gradle 目标切 JDK 25;JUnit 跑测试套,重点验证默认 GC 切换(G1 → 分代 ZGC)的业务影响;用
-Xlog:gc*:file=gc.log跑 24h 压测,对比 Java 21 G1 的暂停时间 + 吞吐。 - 阶段 3(1-2 月)切流期:单实例跑 1 周,监控ZGC 暂停时间分布(应该 < 1ms)+ 吞吐(应该持平或微增)+ 堆使用(分代 ZGC 比 G1 多 5-10% 堆开销因为分代元数据)。
- 阶段 4(全量):全量切。保留 JDK 21 镜像至少 1 个月,回滚窗口 < 5 分钟。
Java 25 性能数据(OpenJDK 官方 benchmark + 业内真实数据):
- 分代 ZGC vs G1:16GB 堆下分代 ZGC 平均暂停 < 1ms(P99 < 5ms),G1 平均暂停 50-200ms(P99 500ms+)。ZGC 在 P99 延迟优势最大(99% 请求的 GC 暂停 < 1ms)。
- 紧凑对象头:100 万个小对象(每个 16 字节)测试,启用紧凑对象头后堆使用从 16MB → 12.8MB(20% 节省);GC 暂停减少 10-15%(扫对象数减少)。
- Scoped Values vs ThreadLocal:100K 虚拟线程 × 5 个上下文,ThreadLocal 副本 500K 个,ScopedValue 0 副本(100% 内存节省)。
ScopedValue.get()比ThreadLocal.get()快 5-10 倍(无 hash 查找)。 - 模块导入:仅影响编译期,不影响运行时性能。
- 结构化并发(Preview 5):跟 CompletableFuture 比,调试期可读性提升 10 倍(JFR 火焰图能看清父子调用链);运行时性能持平。
Spring Boot 3.5 + Java 25 迁移要点:
- Spring Boot 3.5 GA(预计 2025-11):支持 Java 25(最低要求 Java 17)
- Spring Framework 6.2:Scoped Values 原生集成——
RequestContextHolder从 ThreadLocal 改 ScopedValue - Spring Boot 3.5 默认不开虚拟线程(需手动
spring.threads.virtual.enabled=true)—— 升级后先关做对比再开 - JEP 511 模块导入:Spring Boot 3.5 自动生成的项目模板用
import module java.base;风格(节省 import 行数) - 生产建议:CRUD 应用 / 微服务 / 阻塞 IO 应用直接升级 + 开虚拟线程 + 用 Scoped Values;响应式应用保持现状
- 升级路径:Spring Boot 3.2.x → Spring Boot 3.3.x → Spring Boot 3.5.x(要求 Java 17,可选 Java 25)
Java 25 GC 选择决策树:
| |
Scoped Values 迁移 ThreadLocal 清单(生产代码盘点用):
- 搜索 ThreadLocal 用法:
grep -rn "ThreadLocal" src/main/java/ - 分类:
- Web 请求上下文(userId / traceId / locale)→ ScopedValue(JEP 506)
- 数据库连接 / 事务上下文 → Spring 6.2+ 已自动转 ScopedValue,业务代码不用动
- 缓存 / 性能上下文(如 Caffeine size 计算) → 保留 ThreadLocal(不在请求作用域)
- InheritableThreadLocal(父子线程传递) → ScopedValue(自动继承,无需 Inheritable 机制)
- 逐个迁移:每个 ThreadLocal 改 ScopedValue,
set()/remove()改ScopedValue.where().run()块 - 测试:JUnit 跑 + 集成测试覆盖父子线程传递场景
- 监控:JFR
jdk.ScopedValue事件看使用频率
Java 25 长期生产建议:
- 新项目直接用 Java 25(LTS + 现代特性)
- Java 21 老项目升 Java 25(性能 + Scoped Values + 分代 ZGC 优势)
- Java 8/11/17 老项目——Java 25 是终点 LTS,应计划升级;不升级则面临 Oracle 商业支持到期(Java 8 Extended 2030-12 结束)
- AI / 大数据项目——Java 25 + 分代 ZGC + 虚拟线程三件套是 2025 年最强组合
- 嵌入式 / 32-bit x86 项目——Java 25 移除 32-bit x86(JEP 503),需迁 64-bit 或保留 Java 21
§8 系列展望 + Java 26/29 LTS 预告
本系列下阶段
本系列覆盖 Java 8/11/17/21/25 五个 LTS。下阶段扩展方向:
- 横向专题:「JVM GC 大全」「JFR 实战」「JVM 参数调优 300 问」
- Java 9-16 中间版本:「Java 9 模块系统」「Java 10 var」「Java 14 switch 表达式(Preview)」
- 新 LTS:「Java 26 LTS(预计 2026-09)」「Java 29 LTS(预计 2029-09)」
Java 26 LTS(预计 2026-09)
按 LTS 节奏(每 3 年一个),Java 26 预计 2026-09 发布。预期 JEP:
- 字符串模板(如果 JEP 459 重新引入)
- Vector API 孵化转正
- 紧凑对象头扩展(更多平台)
- Scoped Values 配套生态(Spring / Micronaut / Helidon)
Java 29 LTS(预计 2029-09)
按节奏 2029-09 发布。届时虚拟线程 / Scoped Values / 结构化并发 / 分代 ZGC 生态将完全成熟,是 2030 年后新项目的事实标准。
持续关注:本系列长期更新,新 LTS 上市时续写。
