拓展阅读
jdk19 有哪些新特性
JDK 19 引入了一系列新特性,旨在提升 Java 开发的效率和应用程序的性能。以下是 JDK 19 的一些主要新特性:
-
JEP 405: Record Patterns (Preview) - 记录模式预览,允许开发者在模式匹配中使用更简洁、更具可读性的语法,以匹配具有特定属性和行为的对象。
-
JEP 422: Linux/RISC-V Port - 支持在 Linux/RISC-V 平台上运行 Java 应用程序,扩展了 Java 应用程序的硬件选择范围。
-
JEP 424: Foreign Function & Memory API (Preview) - 引入外部函数和内存 API,允许 Java 代码调用其他编程语言编写的函数,并直接访问和操作 Java 堆内存,从而提高应用程序的性能。
-
JEP 425: Virtual Threads (Preview) - 虚拟线程预览,提供了一种轻量级的线程实现,由 JDK 而不是 OS 实现,可以显著减少编写、维护和观察高吞吐量并发应用程序的工作量。
-
JEP 426: Vector API (Fourth Incubator) - 向量 API 第四次孵化,提供了一种处理向量数据的方式,允许开发者高效地处理向量数据,提高应用程序的性能。
-
JEP 427: Pattern Matching for switch - 模式匹配扩展到
switch
语句,允许针对多个模式测试表达式,每个模式都有特定的操作,从而简化代码并提高安全性。 -
JEP 428: Structured Concurrency (Incubator) - 结构化并发孵化,旨在通过结构化并发库简化多线程编程,提高可靠性和可观测性【
JEP 405: Record Patterns (Preview)
JEP 405 引入了记录模式(Record Patterns)作为 Java 语言的一个预览特性,它是模式匹配功能的一部分,允许开发者以声明式的方式从记录类中提取组件。
记录模式建立在 Java 16 引入的模式匹配特性之上,并在 Java 17 和 Java 18 中得到进一步的发展。
以下是 JEP 405 的一些关键点:
- 目的:
- 记录模式旨在简化从记录(record)类型中提取数据的过程,使得相关代码更加简洁和易于理解。
- 语法:
- 记录模式通过在
instanceof
关键字后使用圆括号内的模式来引入,例如:if (obj instanceof Point(int x, int y)) { // 可以直接使用 x 和 y }
- 记录模式通过在
- 与记录类的结合:
- 记录模式与 Java 16 中引入的记录类(Record)特性紧密结合,记录类是一种特殊的类,它以声明式的方式描述了一组浅拷贝的组件。
- 提取数据:
- 开发者可以使用记录模式在
instanceof
表达式中直接提取记录的组件,而不需要显式地创建记录实例。
- 开发者可以使用记录模式在
- 预览特性:
- 作为一个预览特性,JEP 405 允许开发者试用记录模式,并为语言的未来发展提供反馈。
- 示例:
- 假设有一个记录类
Point
,它有两个整型组件x
和y
,可以这样使用记录模式:record Point(int x, int y) {} Object obj = new Point(3, 4); if (obj instanceof Point(int x, int y)) { System.out.println("X coordinate: " + x + ", Y coordinate: " + y); }
- 假设有一个记录类
- 未来展望:
- 根据开发者社区的反馈,记录模式可能会在未来的 Java 版本中得到进一步的改进和完善。
- 兼容性:
- 作为预览特性,JEP 405 不会影响现有代码的运行,但开发者需要注意,预览特性可能在最终版本中有所变化。
JEP 405 进一步扩展了 Java 语言的模式匹配能力,使得处理记录类型更加方便和直观。
JEP 422: Linux/RISC-V Port
JEP 422 是关于将 Java 移植到 Linux/RISC-V 平台的提案。RISC-V 是一种开源指令集架构(ISA),它因其开放性、灵活性以及日益增长的生态系统而受到关注。以下是 JDK 19 中 JEP 422 的一些关键点:
- 支持的硬件:
- RISC-V 是一种免费且开源的指令集架构,被设计用于各种计算设备,从小型嵌入式系统到大型数据中心计算机。
- 移植的目的:
- 通过支持 Linux/RISC-V,Java 应用程序能够在更多类型的硬件上运行,从而扩展了 Java 生态系统的覆盖范围。
- 移植的范围:
- JDK 19 的移植工作支持 RISC-V 的 64 位通用配置(RV64GC),这是 RISC-V 指令集的一个变种,广泛用于服务器和数据中心环境。
- HotSpot VM 选项:
- 该移植支持多种 HotSpot VM 选项,包括模板解释器、客户端 JIT 编译器、服务端 JIT 编译器,以及包括 ZGC 和 Shenandoah 在内的所有当前主线垃圾收集器。
- 开发状态:
- 根据搜索结果,JEP 422 的移植工作基本完成,重点在于将该端口集成到 JDK 的主线存储库中。
- 对开发者的意义:
- 对于 Java 开发者而言,JEP 422 意味着他们可以为基于 RISC-V 架构的系统开发和部署 Java 应用程序。
- 生态系统的扩展:
- 此移植工作有助于 RISC-V 生态系统的成长,因为它提供了对广泛使用的 Java 编程语言的支持。
- 未来展望:
- 随着 JDK 19 的发布,我们可以期待未来会有更多的特性和改进,以支持在 RISC-V 硬件上运行 Java 应用程序。
- 社区的参与:
- 开源社区在 RISC-V 的发展中扮演了重要角色,JEP 422 的实现进一步促进了开源社区与 Java 生态系统的合作。
JEP 422 通过将 Java 环境移植到 RISC-V,不仅加强了 Java 作为一个跨平台语言的地位,而且也促进了 RISC-V 架构的普及和应用。
这对于希望在新兴硬件平台上使用 Java 语言的开发者来说是一个激动人心的发展。
JEP 424: Foreign Function & Memory API (Preview)
JEP 424 引入了 Foreign Function & Memory API (FFM API),作为 JDK 19 的一个预览特性。
这个 API 提供了一种方式,使得 Java 程序能够更高效、更安全地与 Java 运行时之外的代码和数据进行互操作。
以下是 JEP 424 的一些关键点:
- 互操作性:
- FFM API 允许 Java 代码调用用 C 或 C++ 等语言编写的本地库中的函数,并安全地访问不受 JVM 管理的本地内存。
- 性能提升:
- 与 JNI(Java Native Interface)相比,FFM API 提供了一种更高效的方式来进行 Java 与本地代码的互操作,减少了性能开销。
- 安全性增强:
- 通过 FFM API,可以更安全地执行原本需要
Unsafe
类完成的操作,因为 FFM API 提供了对内存访问的更严格的控制和检查。
- 通过 FFM API,可以更安全地执行原本需要
- 简化 JNI:
- FFM API 旨在简化 JNI 的复杂性,JNI 虽然功能强大,但使用起来相对繁琐且容易出错。
- 内存管理:
- FFM API 提供了对本地内存分配和管理的控制,允许开发者分配和释放内存,并在必要时将内存映射到 Java 对象。
- API 组件:
- FFM API 包括
Linker
、FunctionDescriptor
、MemorySegment
、MemoryAddress
和SymbolLookup
等关键类和接口。
- FFM API 包括
- 预览特性:
- 作为一个预览特性,JEP 424 允许开发者提前试用 FFM API,并为语言的未来发展提供反馈。
- 未来展望:
- 根据开发者社区的反馈,FFM API 可能会在未来的 Java 版本中得到进一步的改进和完善。
- 使用示例:
- 假设有一个 C 语言的函数
int strlen(const char *s);
,通过 FFM API,可以获取这个函数的方法句柄,并在 Java 中调用它。
- 假设有一个 C 语言的函数
- JEP 进展:
- FFM API 在 JDK 17 中作为孵化器项目引入(JEP 412),在 JDK 18 中进行了第二轮孵化(JEP 419),在 JDK 19 中作为预览特性提供(JEP 424),并在 JDK 20 中进行了第二次预览(JEP 434),最终目标是成为 Java 平台的正式组成部分。
JEP 424 的引入是 Java 在内存管理和系统级编程方面的一个重要进步,它为 Java 开发者提供了一个强大的工具来访问和操作本地资源,同时提高了性能和安全性。
JEP 425: Virtual Threads (Preview)
JEP 425 引入了虚拟线程(Virtual Threads)作为 JDK 19 的一个预览特性,这是 Project Loom 的一部分,旨在通过提供轻量级的线程实现来改进 Java 的并发模型。
以下是 JEP 425 的一些关键点:
- 轻量级线程:
- 虚拟线程是 JDK 实现的轻量级线程,它们不像传统的 OS 线程那样消耗大量资源。这允许创建数以百万计的线程,而不会像传统线程那样遇到可伸缩性问题。
- 并发性能:
- 由于虚拟线程的轻量级特性,它们可以显著提高高并发应用程序的性能,尤其是在 I/O 密集型和事件驱动的应用程序中。
- 简化并发编程:
- 虚拟线程使得并发编程更加容易和直观。开发者可以使用熟悉的线程 API 来编写并发代码,而不必担心线程管理的复杂性。
- 与现有代码的兼容性:
- 虚拟线程旨在与现有的 Java 并发代码库兼容,这意味着现有的线程代码可以无缝地迁移到虚拟线程模型。
- 结构化并发:
- JEP 425 还引入了结构化并发的概念,这是一种编程范式,它通过将线程的创建和作用域限制在特定的代码块中,来简化错误处理和资源管理。
- 协程支持:
- 虚拟线程为协程提供了基础设施,这允许开发者以声明式的方式编写非阻塞代码,而无需复杂的回调或异步编程模式。
- 预览特性:
- 作为一个预览特性,JEP 425 允许开发者提前试用虚拟线程,并为语言的未来发展提供反馈。
- 性能考量:
- 虚拟线程的设计考虑了性能,尽管它们是轻量级的,但 JDK 实现确保了它们的执行效率和可伸缩性。
- 未来展望:
- 虚拟线程是 Project Loom 的核心特性之一,预计在未来的 JDK 版本中,虚拟线程将正式成为 Java 平台的一部分。
- 使用示例:
- 开发者可以使用
Thread.startVirtual()
方法来创建和启动虚拟线程,这与传统的Thread.start()
方法非常相似,但底层实现更为高效。
- 开发者可以使用
JEP 425 的引入是 Java 语言在并发编程方面的重大进步,它为开发者提供了一种新的工具来编写高效、可伸缩且易于管理的并发应用程序。
虚拟线程和普通的线程有什么区别?
虚拟线程(Virtual Threads)与普通线程(通常指的是操作系统线程,OS Threads)在几个关键方面有显著的区别。
以下是虚拟线程的一些主要特点及其与普通线程的对比:
- 资源消耗:
- 虚拟线程:非常轻量级,创建和上下文切换的开销小,可以创建数以百万计的虚拟线程而不会显著影响性能。
- 普通线程:相对较重,每个线程都需要操作系统分配独立的栈内存,创建和上下文切换的开销较大。
- 调度:
- 虚拟线程:由 Java 虚拟机(JVM)进行调度,而不是直接由操作系统调度。
- 普通线程:由操作系统的调度器直接管理,通常与 CPU 核心紧密关联。
- 可伸缩性:
- 虚拟线程:由于其轻量级特性,更适合大规模并发场景,可以轻松处理大量并发任务。
- 普通线程:由于资源消耗较大,当线程数量增多时,性能会显著下降,受到操作系统资源和调度开销的限制。
- 编程模型:
- 虚拟线程:允许开发者以更简单的方式编写并发代码,类似于编写顺序代码,同时避免了复杂的多线程管理问题。
- 普通线程:编程模型更复杂,需要开发者管理线程的生命周期、同步和其他并发问题。
- 阻塞和非阻塞操作:
- 虚拟线程:可以执行非阻塞操作而不会直接影响 JVM 的性能,因为 JVM 可以在后台运行其他虚拟线程。
- 普通线程:如果执行阻塞操作,如 I/O 等待,可能会阻塞整个线程,影响应用程序的响应性。
- 成本:
- 虚拟线程:通常不涉及操作系统层面的调度和资源分配,因此成本较低。
- 普通线程:每次创建和切换都有显著的 CPU 和内存成本。
- 与协程的兼容性:
- 虚拟线程:为协程提供了底层支持,使得开发者可以更容易地实现协程编程。
- 普通线程:不直接支持协程,需要额外的库或框架来实现协程行为。
- 错误处理和资源管理:
- 虚拟线程:可以利用结构化并发的概念,简化错误处理和资源管理。
- 普通线程:通常需要更复杂的错误处理和资源管理策略。
虚拟线程的设计目标是提供一种更高效、更简单的并发编程方式,特别是在 I/O 密集型和高并发的应用场景中。
通过减少资源消耗和提高可伸缩性,虚拟线程有助于开发者构建性能更强、更易于维护的并发应用程序。
JEP 426: Vector API (Fourth Incubator)
JEP 426: Vector API (Fourth Incubator) 是 Java 19 中的一个提案,旨在通过向 Java 语言引入 Vector API 来表达在支持的 CPU 架构上进行的向量计算。
Vector API 允许开发者编写能够被编译器优化为硬件向量指令的代码,从而在某些计算密集型任务中获得比标量计算更好的性能。
以下是关于 JEP 426 的一些关键点:
- 目标和动机:
- 提供一个清晰、简洁的 API,用于表达一系列由循环内可能带有控制流的向量操作组成的向量计算。
- 该 API 应该是 CPU 架构不可知的,允许在支持向量指令的多架构上实现。
- 在 x64 和 AArch64 架构上,Java 运行时(特别是 HotSpot C2 编译器)能够可靠地将运行时编译和性能优化。
- 向量表示:
- 向量由抽象类
Vector<E>
表示,其中E
是基本类型的装箱类型,如Integer
、Float
等。 - 向量具有一个“形状”,定义了向量的大小(以位为单位),影响向量如何映射到硬件向量寄存器。
- 向量由抽象类
- 向量种类(Vector Species):
- 由元素类型和形状确定的向量种类,由
VectorSpecies<E>
表示。
- 由元素类型和形状确定的向量种类,由
- 内存段(MemorySegments):
- 增强 API 以支持从
MemorySegments
加载和存储向量,这是 JEP 424: Foreign Function & Memory (FFM) API (预览) 的一部分。
- 增强 API 以支持从
- 运行时编译:
- Vector API 有两种实现:一种是用 Java 实现的操作,功能完整但不是最优的;另一种是为 HotSpot C2 运行时编译器定义的内联向量操作,以便在可用时将向量计算编译为适当的硬件寄存器和向量指令。
- 性能和测试:
- 将开发组合单元测试以确保所有操作、所有支持的类型和形状以及各种数据集的覆盖。
- 将开发性能测试以确保性能目标得到满足,并且向量计算有效地映射到向量指令。
- 风险和假设:
- 存在 API 可能偏向 x64 架构上支持的 SIMD 功能的风险,但通过支持 AArch64 来缓解。
- 目前的 API 使用装箱类型作为原始类型的代理,这是由于 Java 泛型对原始类型的限制。预计随着 Project Valhalla 引入更强大的泛型,当前决策将显得尴尬,可能需要改变。
- 未来工作:
- 预计将增强实现以改进包含向量化代码的循环的优化,并随着时间的推移逐步提高性能。
- 考虑为循环展开和矩阵操作定义合成向量形状,并考虑排序和解析算法的适当支持。
- 其他信息:
- JEP 426 是在 JDK 16 作为孵化 API 引入的,随后在 JDK 17 和 JDK 18 中经历了进一步的孵化。
- 在 JDK 19 中,Vector API 作为第四次孵化,继续收集反馈并进行改进。
这个 JEP 是为了提高 Java 在现代硬件上的性能,特别是对于那些可以利用 SIMD(单指令多数据)指令集的 CPU。通过 Vector API,开发者可以编写更接近硬件的代码,从而在需要大规模并行处理的计算中获得性能提升。
JEP 427: Pattern Matching for switch
JEP 427: Pattern Matching for switch (Third Preview) 是 Java 19 中的一个提案,它为 switch
语句和表达式引入了模式匹配功能。这是继 Java 17 (JEP 406) 和 Java 18 (JEP 420) 之后的第三次预览。此功能旨在提高 switch
结构的表达能力和安全性,允许开发者使用模式来匹配 switch
的选择器表达式的值。
以下是 JEP 427 的一些关键点:
-
模式匹配的扩展:在 Java 16 中,
instanceof
操作符已经支持模式匹配。JEP 427 将这种模式匹配扩展到switch
表达式和语句中,允许在case
标签中使用模式,而不仅仅是常量。 -
类型模式:可以为
switch
选择器表达式指定类型模式,这允许更精细的控制流结构,并且可以减少代码量并提高可读性。 -
守卫模式(Guarded Patterns):在模式匹配中,守卫模式允许开发者在
case
标签中加入额外的布尔表达式,这样可以在匹配时加入额外的条件判断。 -
空值处理:JEP 427 改进了
switch
对空值的处理。开发者可以使用case null
来特别处理空输入,或者使用默认的default
标签来处理所有未明确匹配的情况。 -
穷尽性检查:JEP 427 要求
switch
表达式必须穷尽选择器表达式的所有可能值。这意味着必须覆盖所有情况,或者使用default
标签来处理未匹配的情况。 -
模式变量的作用域:模式变量是在模式匹配中声明的局部变量,它们的作用域是流敏感的,即只在成功的模式匹配中声明的变量才会被初始化。
-
与密封类的结合:当
switch
的选择器表达式是密封类时,可以使用密封类的permits
子句来确定switch
是否穷尽。 -
预览特性:由于这是一个预览特性,开发者需要使用
--enable-preview
参数来编译和运行使用此特性的代码。 -
未来工作:JEP 427 还提到了未来的一些可能改进,包括对基本类型的支持、类如何声明解构模式以及增加 AND 和 OR 模式以提供更多的表达能力。
-
依赖关系:此 JEP 建立在
instanceof
的模式匹配 (JEP 394) 和switch
表达式 (JEP 361) 的增强上。预计它还将与记录模式 (JEP 405) 和动态常量 (JEP 309) 结合使用。
JEP 427 的目标是通过允许在 case
标签中使用模式来扩展 switch
表达式和语句的表达能力,并允许在需要时放宽对 switch
的历史限制。
同时,它旨在确保所有现有的 switch
表达式和语句在不做任何改变的情况下继续编译和执行。
更多详细信息可以在 OpenJDK 的官方文档中找到。
JEP 428: Structured Concurrency (Incubator)
JEP 428: Structured Concurrency (Incubator) 是 Java 19 中的一个提案,旨在简化多线程编程。这个特性通过引入结构化并发的概念,使得开发者能够以一种更直观和安全的方式来编写和管理并发代码。以下是关于 JEP 428 的一些关键点:
-
结构化并发的目标:结构化并发旨在将多线程或子任务作为单个工作单元来对待,从而简化错误处理和取消操作,提高程序的可靠性和可观测性。
-
StructuredTaskScope 类:开发人员可以使用
StructuredTaskScope
类来组织他们的并发代码。这个类将一组子任务视为一个单元,子任务通过单独的线程创建,并连接成一个单元,也可以作为一个单元进行取消。 -
生命周期管理:在结构化并发中,子任务的生命周期与创建它们的代码块绑定。这意味着,如果父任务完成,所有未完成的子任务都将被取消。这样可以避免线程泄漏和资源浪费。
-
错误处理:如果子任务中的任何一个失败,
StructuredTaskScope
可以帮助取消其他未完成的任务,并将异常传递给父任务。这简化了错误处理机制。 -
两种策略:
StructuredTaskScope
提供了两种策略:ShutdownOnFailure
和ShutdownOnSuccess
。ShutdownOnFailure
会在任何一个子任务失败时取消所有任务,而ShutdownOnSuccess
会在第一个子任务成功完成时取消其他所有任务。 -
虚拟线程集成:结构化并发与虚拟线程(由 Project Loom 提供)紧密集成。虚拟线程是 JVM 管理的轻量级线程,适合编写高吞吐量的并发应用程序。
-
JDK 19 状态:在 JDK 19 中,结构化并发作为一个孵化器阶段的特性被引入,允许开发者开始尝试这个 API,同时它还在积极开发和改进中。
-
编译和运行:要使用结构化并发,需要在编译和运行时添加
--enable-preview
参数,并且需要添加jdk.incubator.concurrent
模块。 -
未来发展:JEP 428 预计将继续发展并在 JDK 的未来版本中提供更稳定的 API。它可能会与 Project Loom 中的其他特性(如虚拟线程)更紧密地集成,以提供更强大的并发编程模型。
结构化并发是 Java 并发编程领域的一个重要进展,它有助于开发者编写更清晰、更安全且更易于维护的并发代码。
通过将并发任务组织为一个单元,JEP 428 有助于减少并发编程中的复杂性,并提高程序的整体健壮性。
更多详细信息可以在 OpenJDK 的官方文档中找到。