1. 概述
Java 20 于 2023 年 3 月 21 日发布,是当前最新的短期增量版本,基于 Java 19 构建。它包含 JEP 2.0 中提到的七项重要 JDK 增强提案(JEP)。JEP 流程用于评估 JDK 的增强提案。Java 20 的大部分更新都是对早期版本引入功能的改进或增强。
值得注意的是,Oracle JDK 20 不是长期支持版本,因此它只会收到更新直到 Java 21 发布。
本文将探讨其中一些新特性。
2. 作用域值(Scoped Values)(JEP 429)
许多 Java 应用程序需要在组件或模块之间共享数据。通常这些模块基于线程,因此必须保护共享数据不被修改。
我们一直使用 ThreadLocal
类型的变量来实现组件间的数据共享,但它存在一些问题:
-
ThreadLocal
变量是可变的,其 API 允许访问get()
和set()
方法 - 可能导致内存泄漏,因为
ThreadLocal
变量的值会一直保留,直到显式调用remove()
或线程退出 - 当使用大量线程时可能导致内存占用过大,因为子线程会继承父线程的
ThreadLocal
变量
为解决这些问题,Java 20 引入了作用域值用于在线程内和跨线程共享数据。
作用域值提供了一种简单、不可变且可继承的数据共享方式,特别适合处理大量线程的场景。
ScopedValue
是一个不可变值,在线程的有限执行周期内可读。由于不可变,它允许在线程执行期间安全轻松地共享数据,且无需作为方法参数传递。
我们可以使用 ScopedValue
类的 where()
方法为线程的有限执行周期设置变量值。一旦通过 get()
获取数据后,就无法再次访问。
当线程的 run()
方法执行完毕后,作用域值会恢复为未绑定状态。在线程内部可以使用 get()
方法读取作用域值变量的值。
3. 记录模式(Record Patterns)(JEP 432)
JDK 19 已将记录模式作为预览功能引入。
Java 20 提供了改进和精炼的记录模式版本。本版本的主要改进包括:
- 新增对泛型记录模式参数的类型推断支持
- 新增支持在增强 for 循环头部使用记录模式
- 移除了命名记录模式的支持(之前可为记录模式提供可选标识符)
本版本旨在通过模式匹配表达更完善、可组合的数据查询,同时不改变类型模式的语法和语义。
4. Switch 的模式匹配(JEP 433)
Java 20 提供了switch 表达式和语句模式匹配的精炼版本,主要优化了 switch 表达式的语法。该特性首次在 Java 17 中引入,后续在 Java 18 和 19 中持续改进,扩展了 switch 语句和表达式的适用性。
本版本的主要变化包括:
- 对枚举类使用 switch 表达式或模式时,现在会抛出
MatchException
(之前运行时无匹配标签会抛出IncompatibleClassChangeError
) - 改进了 switch 标签的语法
- 在 switch 表达式/语句及其他支持模式的结构中,新增对泛型记录模式参数的类型推断支持
5. 外部函数与内存 API(JEP 434)
Java 20 整合了早期版本中外部函数与内存 (FFM) API 的改进和优化。这是第二个预览 API。
外部函数与内存 API 允许 Java 开发者访问 JVM 外部的代码并管理堆外内存(即 JVM 不管理的内存)。 FFM API 旨在为 Java 本地接口 (JNI) 提供更安全、更完善的纯 Java 替代方案。
主要优化包括:
- 统一了
MemorySegment
和MemoryAddress
抽象,现在可以通过空间边界确定与内存段关联的地址范围 - 通过增强密封的
MemoryLayout
层次结构,促进在 switch 表达式/语句中使用模式匹配 - 将
MemorySession
拆分为Arena
和SegmentScope
,便于跨维护边界共享内存段
6. 虚拟线程(JEP 436)
虚拟线程 最初在 JEP 425 中提出,并在 Java 19 中作为预览功能发布。Java 20 提出第二个预览版,旨在收集更多使用反馈和改进建议。
虚拟线程是轻量级线程,能减少编写、维护和观察高吞吐量并发应用程序的工作量。它使使用现有 JDK 工具调试和排查服务器应用问题变得更容易,对服务器应用扩展很有帮助。
⚠️ 需要注意:传统的 Thread
实现仍然存在,虚拟线程并非旨在替代 Java 的基本并发模型。
自首个预览版以来的次要变更:
- Thread 类中之前引入的方法——
join(Duration)
、sleep(Duration)
和threadId()
——在 Java 20 中转为正式特性 - Future 类中新增的检查任务状态和结果的方法——
state()
和resultNow()
——在 Java 20 中转为正式特性 -
ExecutorService
现在扩展了AutoCloseable
接口 - JDK 19 中对传统线程分组 API
ThreadGroup
的降级处理转为永久特性(ThreadGroup
不适用于虚拟线程分组)
7. 结构化并发(JEP 437)
结构化并发由 JEP 428 提出,并在 JDK 19 中作为孵化 API 发布。本 JEP 提议在 JDK 20 中重新孵化该 API 且基本无变更,以便收集更多反馈。
目标是通过引入结构化并发 API 简化多线程编程。它将执行相似任务的多个线程分组为单个工作单元,从而提高可靠性,改进错误处理和线程取消机制。此外,它推广了一种改进的并发编程方式,旨在防范线程取消带来的常见风险。
唯一变化是:更新后的 StructuredTaskScope
支持任务作用域中创建的线程继承作用域值,现在可以更方便地在多个线程间共享不可变数据。
8. 向量 API(JEP 438)
向量 API 最初由 JEP 338 提出,在 JDK 16 中作为孵化 API 集成。本版本(第五次孵化)是在之前所有 Java 版本中多轮孵化和集成后的延续。
向量 API 用于在支持的 CPU 架构上表达 Java 中的向量计算。向量计算实际上是对向量的一系列操作。向量 API 旨在提供比传统标量计算更优化的向量计算手段。
与 Java 19 相比,本版本未引入 API 变更,但包含一些错误修复和性能增强。
✅ 向量 API 的开发与 Project Valhalla 紧密对齐,未来将适配 Project Valhalla 的增强特性。
9. 总结
Java 20 在过去版本的多个特性基础上持续迭代,包括记录模式、switch 表达式模式匹配、FFM API、虚拟线程等。它还新增了作用域值等孵化特性,并对结构化并发和向量 API 等重新孵化的特性进行了增强。
本文讨论了 Java 20 增量版本中引入的部分特性和变更。完整变更列表请参考 JDK 发布说明。