JDK 21 LTS 高频特性回顾与升级

共 18 题
📑 题目列表 18 题
#
★★★

1. JDK 21 LTS 相比 17 LTS 的关键特性(虚拟线程/结构化并发/模式匹配/记录模式)如何系统性盘点?

请系统性盘点 JDK 21 LTS 相比 JDK 17 LTS 的关键特性,包括虚拟线程、结构化并发、模式匹配与记录模式?

  • 虚拟线程与结构化并发
  • 模式匹配与记录模式
  • 其他关键特性(分代 ZGC、序列集合等)

JDK 21 相比 17 引入了一批关键特性。虚拟线程(JEP 444):轻量级线程,大幅降低高并发 IO 场景的线程成本,是 Loom 的核心交付。结构化并发(JEP 453,预览):通过 StructuredTaskScope 组织并发任务,可取消、有作用域。模式匹配(JEP 441):switch 模式匹配转正,支持类型模式、守卫、穷尽性检查,让分支代码更简洁。记录模式(JEP 440,转正):可解构 record 与嵌套记录,配合模式匹配 switch 使用。其他特性:分代 ZGC(JEP 439)、Sequenced Collections(JEP 431)、Key Encapsulation Mechanism API(JEP 452)、字符串模板(JEP 430,预览)、未命名模式与变量(JEP 443,预览)等。系统性盘点应关注"并发模型(虚拟线程/结构化)、代码表达(模式/记录)、GC(分代 ZGC)、集合 API(Sequenced)"几个主线,并评估升级收益。

21 相比 17 的核心是"并发与表达力"的双重跃升:虚拟线程/结构化并发改变并发模型,模式匹配/记录模式提升代码表达,分代 ZGC 优化 GC。系统盘点可从这几条主线展开。

#
★★★

2. Sequenced Collections(JEP 431)解决了集合的哪些一致性痛点,与 List/Deque/SortedSet 的兼容关系?

请说明 Sequenced Collections(JEP 431)解决了集合的哪些一致性痛点,以及它与 List/Deque/SortedSet 的兼容关系?

  • 顺序集合的痛点(无序访问、首尾元素)
  • SequencedCollection 接口
  • 与 List/Deque/SortedSet 的关系

传统集合访问首尾元素、逆序访问等操作不一致:List 有 get(0)/get(last),Deque 有 getFirst/getLast,SortedSet 有 first()/last(),但接口不统一,很多集合没有统一 API。Sequenced Collections(JEP 431)引入 SequencedCollection(含 getFirst/getLast/reversed/addFirst/addLast)、SequencedSetSequencedMap,统一了"有顺序集合"的接口。兼容关系:ListDeque 都成为 SequencedCollection 的子类型,SortedSet/NavigableSet 实现 SequencedSetSortedMap/NavigableMap 实现 SequencedMap。这是纯接口扩展,不破坏现有实现,使既有集合类自动获得统一的首尾访问与逆序 API。价值在于统一 API、消除"不同集合不同写法"的痛点。

Sequenced Collections 解决的是"顺序集合无统一 API"的一致性痛点:通过新增接口并让现有集合继承,实现统一的首尾访问与逆序。纯接口扩展保证了向后兼容。

#
★★★

3. 记录模式(Record Patterns)与嵌套解构在业务代码中的实际收益,与模式匹配 switch 如何组合?

请说明记录模式(Record Patterns)与嵌套解构在业务代码中的实际收益,以及它与模式匹配 switch 如何组合?

  • Record Pattern 的解构能力
  • 嵌套解构
  • 与模式匹配 switch 的组合

记录模式(Record Patterns)允许通过模式匹配解构 record 的组件,如 if (o instanceof Point(int x, int y)) 直接提取字段,避免手动强转与 getter 调用。嵌套解构支持复杂结构:if (o instanceof Circle(Point(int x, int y), int radius)) 可一次解构多层,从容器/record 中提取内部字段。与模式匹配 switch 组合时,可对 record 做类型匹配 + 解构 + 守卫,实现穷尽性的分支处理,如 switch (shape) { case Circle(Point(int x, int y), int r) -> ...; case Rect(...) -> ...; }。业务收益:代码更简洁、类型安全、可读性高,尤其适合处理 DTO、树形结构、事件反序列化等场景;配合密封类可实现穷尽性检查,编译期保证所有分支覆盖。

记录模式的价值是"把解构从手写样板代码变为声明式":嵌套解构与模式匹配 switch 组合,让复杂对象处理简洁且类型安全。它与密封类配合可实现穷尽性保障。

#
★★★

4. 分代 ZGC(JEP 439)相比非分代 ZGC 的停顿改进,什么场景下收益最大?

请说明分代 ZGC(JEP 439)相比非分代 ZGC 的停顿改进,以及什么场景下收益最大?

  • 分代 ZGC 的机制
  • 停顿改善
  • 收益最大的场景

分代 ZGC(JEP 439)在 JDK 21 中引入,将 ZGC 分为年轻代与老年代,利用"大部分对象短命"的弱分代假设,频繁回收年轻代、较少回收老年代。相比非分代 ZGC(每次全量回收),分代 ZGC 减少了每次回收需要遍历的对象数量,降低回收频率与停顿,并提升吞吐。收益最大化的场景:对象分配率高、短命对象多、堆较大的应用(如频繁创建临时对象的服务、高并发请求处理),此时年轻代回收效率高,整体 GC 停顿与开销显著下降。对低分配率、长命对象多的应用,收益相对有限。分代 ZGC 在保持低停顿(亚毫秒级)的同时改善吞吐,是生产环境默认推荐的分代方案。

分代 ZGC 的价值是"利用弱分代假设降低回收频率":短命对象多时年轻代回收效率高,停顿与吞吐双改善。分配率高的场景收益最大。

#
★★

5. 虚拟线程在生产落地的收益评估,IO 密集服务的吞吐提升与线程池迁移策略

请评估虚拟线程在生产落地的收益,包括 IO 密集服务的吞吐提升与线程池迁移策略?

  • 虚拟线程在 IO 密集场景的收益
  • 线程池迁移策略
  • 落地注意事项

虚拟线程在 IO 密集服务(大量阻塞 IO:数据库、HTTP、消息)收益显著:传统"每请求一平台线程"受线程数限制(平台线程耗内存、上下文切换成本高),虚拟线程成本极低,可承载海量并发,阻塞时自动让渡载体线程,从而提升吞吐。收益评估:IO 密集场景吞吐可数倍提升,线程数与内存占用大幅下降。迁移策略:1) 从"平台线程池"迁移到"虚拟线程"——用 Executors.newVirtualThreadPerTaskExecutor() 或按需创建虚拟线程,替代固定线程池;2) 检查阻塞点——确认依赖的库支持虚拟线程(避免同步块钉住);3) 注意线程局部变量与 ThreadLocal 的滥用(虚拟线程数量大,ThreadLocal 内存开销放大);4) 分阶段:先小流量验证吞吐与稳定性,再逐步扩大。落地注意事项:CPU 密集场景收益有限,需结合场景评估。

虚拟线程收益在"IO 密集、高并发"场景最明显,迁移核心是"替换线程池 + 排查钉住 + 控 ThreadLocal":先评估收益场景,再分阶段迁移,避免盲目全量替换。

#
★★

6. 从 JDK 8/11 直接升级到 21 LTS 的主要兼容性风险与治理清单?

请说明从 JDK 8/11 直接升级到 21 LTS 的主要兼容性风险与治理清单?

  • 跨多个版本的兼容性风险
  • API 移除与行为变更
  • 治理清单与回归

从 JDK 8/11 直接升级到 21 跨越多个版本,风险包括:1) 内部 API 移除——sun.misc.Unsafesun.* 等内部 API 被限制/移除,依赖它们的库需替换;2) 废弃 API 移除——finalize、部分旧 API 被移除;3) 模块化——JDK 9+ 引入模块系统,强封装内部 API,反射访问受限;4) 行为变更——GC 默认值、字符串、序列化、启动参数等变化;5) 字节码版本——class file 版本需 JDK 21 支持;6) 第三方库兼容——依赖库需支持 JDK 21。治理清单:用 jdeps 扫描内部/废弃 API、检查 finalize/Unsafe、升级依赖版本、开启 -Xlint:deprecation/removal、对照 Release Notes 逐项核对行为变更、做全量回归与性能对比。建议分步升级(8→11→17→21)降低排查难度。

跨大版本升级的核心风险是"内部 API、模块化封装、行为变更":治理是关键"用工具扫描 + 逐版本核对 + 分步升级"。理解这些风险是安全升级的前提。

#
★★

7. switch 模式匹配与 record pattern 的嵌套解构在业务代码中的实际收益?

请说明 switch 模式匹配与 record pattern 的嵌套解构在业务代码中的实际收益?

  • switch 模式匹配的表达力
  • 嵌套解构
  • 业务收益

switch 模式匹配与 record pattern 的嵌套解构组合,让业务代码更简洁、类型安全。实际收益:用 switch 对对象做类型匹配 + 解构 + 守卫,替代繁琐的 if/else 链与强转;配合记录模式可嵌套解构,一次提取多层字段;配合密封类实现穷尽性检查,编译期保证所有类型分支覆盖。业务场景:处理多态 DTO、事件分发、规则引擎、树形/嵌套结构解析、重构"instanceof 链"。收益体现在:减少样板代码、降低强转错误、提升可读性,且穷尽性让新增类型时编译器提示遗漏分支。工程上需注意模式匹配的 null 处理与 dart 顺序。

收益核心是"用声明式分支替代命令式样板":类型安全 + 穷尽性 + 解构,让业务代码更聚焦于逻辑本身。适合多态与嵌套结构处理。

#
★★

8. Java 21 的 Key Encapsulation Mechanism API(JEP 452)在应用侧的价值与使用场景?

请说明 Java 21 的 Key Encapsulation Mechanism API(JEP 452)在应用侧的价值与使用场景?

  • KEM API 的原理
  • 抗量子与后量子密码
  • 应用场景

Key Encapsulation Mechanism(KEM, JEP 452)封装了密钥封装机制,如基于椭圆曲线的 ECDH 派生密钥,以及后量子算法(如 ML-KEM/Kyber)。KEM 提供"封装(encapsulate)"与"解封装(decapsulate)"接口,将密钥协商抽象为生成/共享密钥。应用侧价值:为后量子密码(PQC)过渡提供标准 API,当量子计算威胁现有 RSA/ECC 时,可用 KEM 实现抗量子密钥交换;同时标准化了密钥协商的密钥派生。使用场景:TLS 握手密钥协商、安全通信的密钥交换、以及需要装载后量子算法的场景。Java 21 提供 KEM 抽象,未来版本引入 ML-KEM 等后量子算法实现。工程上需关注算法实现与性能,以及向后兼容的密钥协商。

KEM API 的价值在于"抽象密钥封装 + 为后量子密码铺路":通过标准接口接入抗量子算法,应对未来量子威胁。理解其密钥协商语义是应用前提。

#
★★

9. JDK 21 升级的兼容性治理,API 移除、模块化与字节码版本的影响如何?

请说明 JDK 21 升级的兼容性治理,包括 API 移除、模块化与字节码版本的影响?

  • API 移除与废弃
  • 模块化封装
  • 字节码版本影响

JDK 21 升级的兼容性治理需关注三类影响。API 移除:自 JDK 8 起各版本移除/废弃了一批 API(如 finalize、部分废弃类),依赖这些的应用需替换;用 jdeps-Xlint:removal 识别。模块化:JDK 9+ 的模块系统强封装内部 API(sun.*),反射访问受限,需使用 --add-opens 或迁移到公开 API。字节码版本:class file 版本需与 JDK 21 兼容(JDK 21 支持 class 65),但旧版本编译的 class 可能依赖已移除 API,需重新编译。治理方法:建立 API 兼容清单、用工具扫描内部/废弃 API、升级依赖库、启用编译告警、分模块迁移与回归。重点是"先扫后迁、逐项验证"。

兼容性治理的三大影响是"API 移除、模块化封装、字节码版本":工具扫描 + 依赖升级 + 分步回归是核心。理解模块化对反射的限制是治理关键。

#
★★

10. JDK 21 升级后的性能回归验证,GC 行为、JIT 与启动时间对比

请说明 JDK 21 升级后的性能回归验证,包括 GC 行为、JIT 与启动时间对比?

  • GC 行为对比
  • JIT 性能
  • 启动时间

JDK 21 升级后需做性能回归验证。GC 行为:对比升级前后 GC 频率、停顿、堆使用、收集器表现,JDK 21 默认 GC 与 8/11 不同(G1 升级、分代 ZGC 可用),需验证 GC 参数兼容与表现;可用 JFR 采集 GC 数据对比。JIT:对比热点方法的编译质量与吞吐,JDK 21 的 JIT 优化(C2 增强)可能改变性能特征,用基准与压测对比。启动时间:对比启动耗时与类加载,21 的 CDS/AppCDS 可加速启动,长时运行稳定性也需验证。回归方法:建立基准(启动时间、吞吐、延迟、GC),在相同负载下对比新旧版本,用 JFR/火焰图定位差异,必要时调整 GC 与 JVM 参数。结论需基于压测数据而非经验。

性能回归的核心是"同负载对比 + 数据驱动":GC/JIT/启动的差异需用 JFR 与压测量化,避免"升级后感觉变慢"的主观判断。参数调整以数据为准。

#
★★

11. 虚拟线程在 JDK 21 的使用边界,synchronized pinning 与线程池迁移如何?

请说明虚拟线程在 JDK 21 的使用边界,包括 synchronized pinning 与线程池迁移?

  • synchronized pinning 问题
  • 线程池迁移方式
  • 使用边界

JDK 21 虚拟线程的使用边界:synchronized 钉住(pinning)——在同步块内执行阻塞 IO 时,虚拟线程会被钉在载体线程上,无法让渡,导致吞吐下降;JDK 21 尚未完全解决(后续 JEP 491 缓解),因此高并发 IO 场景应避免在 synchronized 内做阻塞 IO,改用显式锁(ReentrantLock)或无锁。线程池迁移:用 Executors.newVirtualThreadPerTaskExecutor() 创建"每任务一虚拟线程"的调度器,替代固定大小平台线程池;对阻塞 IO 密集任务收益明显。使用边界还包含:不吃 CPU 密集任务、ThreadLocal 需谨慎(虚拟线程数量大,ThreadLocal 内存放大)、与依赖"每线程状态"的旧库兼容。迁移时需识别阻塞点与钉住场景,分阶段落地。

JDK 21 虚拟线程的边界主要在"锁定与第三方库":synchronized 钉住是主要限制,ThreadLocal 与大线程数是内存风险。理解边界才能正确迁移与受益。

#

12. Java 21 中未命名模式与变量(JEP 443 预览)与字符串模板(JEP 430,预览)的定位与使用限制?

请说明 Java 21 中未命名模式与变量(JEP 443 预览)与字符串模板(JEP 430,预览)的定位与使用限制?

  • 未命名模式与变量的定位
  • 字符串模板的定位
  • 预览特性的使用限制

未命名模式与变量(JEP 443,预览)允许用 _ 表示"不关心"的模式与变量,如 case _ ->(未命名模式)或 int _ = ...(未命名变量),让代码更简洁,避免为不用的值命名。字符串模板(JEP 430,预览)允许在字符串中嵌入表达式(如 STR."Hello $\{name}"),通过模板处理器构建字符串,简化拼接与格式化。两者在 JDK 21 均为预览版,需 --enable-preview 编译运行,API 可能变更(字符串模板后来被撤回重做)。使用限制:预览特性不稳定、不保证未来兼容,不适合生产依赖;未命名模式/变量不能用于所有位置(如不可用于赋值),字符串模板需理解处理器与转义规则。定位上,两者都是"表达力增强",但需等其转正后再规模化采用。

预览特性的定位是"早期体验 + 意见收集",使用限制是"不稳定、需 --enable-preview、未来可能变更"。生产应等待转正,避免依赖易变 API。

#

13. Project Loom 后续(Loom 2.0)与虚拟线程的已知限制(同步阻塞、线程局部变量)?

请说明 Project Loom 后续(Loom 2.0)与虚拟线程的已知限制,包括同步阻塞与线程局部变量?

  • 虚拟线程的已知限制
  • 同步阻塞与 ThreadLocal
  • Loom 后续演进

虚拟线程的已知限制包括:1) 同步阻塞钉住——synchronized 内阻塞 IO 会把虚拟线程钉在载体线程上(JDK 21 存在,后续 JEP 491 缓解);2) 线程局部变量(ThreadLocal)——虚拟线程数量巨大,ThreadLocal 若被大量使用或未清除,会放大内存占用,且线程局部变量的语义在虚拟线程下需谨慎(虚拟线程复用载体线程);3) 与依赖"每线程池固定容量"的旧代码不兼容;4) 不适合 CPU 密集任务。Project Loom 后续(Loom 2.0)方向包括:修复钉住问题、改进调度、结构化并发的完善、以及与其他特性的整合。工程实践:避免同步块内阻塞、控制 ThreadLocal 使用(用 ScopedValue 替代)、按需迁移、评估收益场景。

虚拟线程限制的核心是"钉住与 ThreadLocal":钉住影响吞吐,ThreadLocal 放大内存。Loom 后续持续缓解,但工程上需主动规避这些限制。

#

14. 从 Java 17 升级到 21 时,Unsafe、内部 API 与反射封装的兼容性风险点如何系统排查?

请说明从 Java 17 升级到 21 时,Unsafe、内部 API 与反射封装的兼容性风险点如何系统排查?

  • Unsafe 与内部 API 的风险
  • 反射封装与模块化
  • 系统排查方法

从 17 升级到 21,Unsafe、内部 API 与反射封装是关键风险点。Unsafesun.misc.Unsafe 是内部 API,21 下仍可通过 --add-opens 访问,但官方不保证,且其部分方法被限制/替代,依赖 Unsafe 的库(如某些并发/序列化库)需验证兼容;应迁移到 FFM 等公开 API。内部 API:sun.* 等内部类在 21 下默认强封装,直接访问会抛 InaccessibleObjectException,需 --add-opens/--add-exports 或迁移。反射封装:模块系统限制对非公开类的反射访问,setAccessible 可能失败。系统排查:用 jdeps 扫描 sun.misc.Unsafe 与内部 API 引用;运行关键测试捕获 InaccessibleObjectException;收集并分析 --add-opens 使用;逐个替换为公开 API;全量回归。目标是"消除对内部 API 的隐式依赖"。

排查核心是"扫描内部 API 引用 + 处理反射封装 + 迁移到公开 API":jdeps 识别、异常捕获定位、add-opens 治理、最终迁移。依赖内部 API 是升级最大隐患。

#

15. 记录模式与密封类的组合使用,模式匹配 switch 的表达式如何?

请说明记录模式与密封类的组合使用,以及模式匹配 switch 的表达式?

  • 记录模式 + 密封类
  • 穷尽性分支
  • switch 表达式

记录模式与密封类组合使用能实现强类型的穷尽性分支。密封类(sealed class)限定允许的继承类型,配合 switch 模式匹配时,编译器可穷尽检查所有可能的类型分支,无需 default 外壳即可保证覆盖。记录模式在分支中解构 record 字段,配合守卫条件精确匹配。如 switch(shape) { case Circle(int r) -> ...; case Rect(int w, int h) -> ...; },若密封类只允许 Circle/Rect,则编译期确认穷尽。组合的价值:类型安全(编译期验证分支覆盖)、可读性(解构 + 分支清晰)、易维护(新增类型时编译器提示遗漏)。这种模式适合表达"类型驱动的多态行为",替代手写 instanceof 链。

记录模式 + 密封类 + switch 三者的组合是"穷尽匹配"的范式:密封类限类型、记录模式解构、switch 穷尽分支。它把类型分派变成编译期可验证的表达式。

#

16. JDK 21 的字符串模板/虚拟线程的工程落地与兼容性风险?

请说明 JDK 21 的字符串模板与虚拟线程的工程落地与兼容性风险?

  • 字符串模板的落地与风险
  • 虚拟线程的落地与风险
  • 兼容性关注点

字符串模板(JEP 430,预览)在 JDK 21 处于预览,需 --enable-preview,且 API 后来被重做,因此生产落地风险高,不建议依赖;应等其转正后再用,当前可用传统拼接或 String.format。虚拟线程(JEP 444,正式)已可落地,重点用于 IO 密集高并发场景,风险包括 synchronized 钉住、ThreadLocal 内存放大、与第三方库兼容。工程落地建议:虚拟线程分阶段灰度(先验证钉住与资源),控制 ThreadLocal,明确收益场景;字符串模板等待稳定。兼容性风险:虚拟线程改变线程模型,依赖"每线程语义"的库需验证;预览特性不向后兼容。整体上,虚拟线程可落地,字符串模板需等待。

落地差异在于"是否正式":虚拟线程已正式、可落地但需注意钉住/ThreadLocal;字符串模板仍预览、风险高、应等待。按正式状态决定采用策略。

#

17. JDK 21 的 Foreign Function & Memory API 预览,与 JNI 的对比如何?

请说明 JDK 21 的 Foreign Function & Memory API(FFM)预览,以及与 JNI 的对比?

  • FFM API 的能力
  • 与 JNI 的对比
  • 工程价值

FFM(Foreign Function & Memory API,JEP 442)在 JDK 21 处于预览,提供安全地调用原生函数与访问原生内存的能力。与 JNI 对比:1) 安全性——FFM 类型安全、有边界检查,避免 JNI 的崩溃风险;JNI 常有内存错误与崩溃。2) 易用性——FFM 纯 Java 编写,无需写 C 代码与 JNI 样板;JNI 需手写 native 方法与 C 实现。3) 性能——FFM 提供高效的方法句柄与内存访问,性能与 JNI 相当或更优。4) 生命周期管理——FFM 可管理原生内存生命周期,避免泄漏。FFM 还替代了 Unsafe 的部分功能。工程价值:让 Java 安全高性能地调用原生库、管理堆外内存,减少 JNI 的维护与崩溃成本。JDK 21 为预览,需 --enable-preview,后续版本转正。

FFM 相比 JNI 的核心优势是"安全 + 易用 + 高性能":类型安全避免崩溃、纯 Java 免 C 样板、高效管理堆外内存。它逐步替代 JNI 与 Unsafe。

#

18. JDK 21 的 API 增强(StringBuilder.repeat、Math 等)在生产代码中的应用

请说明 JDK 21 的 API 增强(如 StringBuilder.repeat、Math 等)在生产代码中的应用?

  • 常用 API 增强
  • 生产应用场景
  • 使用价值

JDK 21 带来一批 API 增强,应用中可提升代码质量。StringBuilder.repeat:重复字符串填充,简化重复 char/string 的构建(如分隔线、缩进)。Math.clamp:限制值范围,替代手写 Math.max/min 嵌套。String.indexOf 泛型化、StringBuilder 便利方法等。此外还有 SequencedCollectionMath 的静态方法、Integer/LongdivCeil/divFloor 等。生产应用:字符串填充、值范围约束、集合首尾访问、整除取整等常见逻辑可更简洁。价值在于减少样板代码、提升可读性与正确性(如 clamp 避免边界错误)。这些是"小而实用"的 API,能提升日常编码体验,但需在代码中主动采用并保持一致的编码规范。

API 增强的价值是"用标准方法替代手写样板":clamp、repeat、divCeil 等让常见逻辑更简洁、更不易错。采用需考虑代码库一致性与可读性。