2023-12-21  阅读(898)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/series/article/1441731195

Java 16 在 2021 年 3 月 16 号发布。

JEP 338:向量 API(孵化器)

在现代计算中,数据密集型操作是非常常见的,例如科学计算、机器学习、图形处理等等,这些操作往往可以通过向量化来加速(即同时对多个数据项执行相同的操作)。但是,Java 缺乏一种官方的、标准的方式来利用硬件的向量计算能力,这就限制了Java在处理这类操作时的性能。

Java 16 引入向量API 来填补这一空缺。向量API提供了一套用于表达向量计算的API,可以在支持SIMD(单指令多数据)的处理器上运行。它使得Java能够更有效地利用现代处理器的向量计算能力,从而提高性能。

API设计为平台无关,但可以在支持的硬件上利用特定的优化。

JEP 347:启用 C++14 语言特性

我们知道 JDK的某些部分是用C++编写的,特别是JVM。随着C++语言的发展,新的标准引入了许多有用的特性,例如更好的类型推断、智能指针、lambda表达式等等,这些都可以帮助提高代码质量和开发效率。但是 JDK 开发主要还是使用旧版C++标准(如C++98),这就限制了可以使用的语言特性。

Java 16 启用 C++ 14 语言,这就标志着允许JDK的开发者在编写JDK源代码时使用C++14标准的语言特性。这样就可以提升 JDK 的开发效率和代码质量了。

JEP 357:将JDK的源代码库从Mercurial迁移到Git

Git是目前最流行的版本控制系统,拥有更广泛的用户基础和社区支持。许多现代的开发工具和服务(如GitHub、GitLab等)都是围绕Git设计的,迁移到Git可以更好地利用这些工具和服务。同时在某些方面,Git提供了比Mercurial更好的性能。

所以,Java 16 将Java开发工具包(JDK)的源代码库从Mercurial迁移到Git的过程。迁移包括将所有代码历史、分支、标签等从Mercurial转移到Git。

JEP 369:将JDK的源代码库托管到GitHub

同上。

JEP 376:ZGC 并发线程处理

ZGC 是 Java 11 中引入的一个实验性垃圾收集器,设计目标是实现低延迟一个可伸缩的、低延迟的垃圾收集器。在 Java 11 到 Java 15 期间,ZGC 已经表现出了卓越的低延迟特性,但在某些情况下,它需要暂停应用线程来处理堆中的引用。

Java 16 引入并发线程处理,旨在将这些暂停转变为并发处理,以进一步降低延迟。该特性的核心是将 ZGC 中的最后一块堆管理工作 — 引用处理(Reference Processing) — 转变为并发执行。

JEP 380:Unix-Domain 套接字通道

Unix-Domain 套接字在 Unix-like 系统中被用于进程间通信(IPC)。与基于网络的 TCP/IP 套接字相比,UDS 提供了更高的数据传输效率和安全性,因为它们仅在同一台机器上的进程之间通信,无需网络堆栈的开销。在 Java 中引入 UDS 支持,意味着 Java 应用程序现在可以更有效地在同一台机器上的进程之间进行通信,这对于需要高效本地通信的应用来说是一个重要的改进。

主要内容包括:

  1. Unix-Domain 套接字的支持:在 java.nio.channels 包中引入了对 Unix-Domain 套接字的支持,使得 Java 程序能够创建和使用 UDS。
  2. SocketChannel 和 ServerSocketChannel 的扩展:这些类被扩展以支持 Unix-Domain 套接字,除了原有的网络套接字功能。
  3. 新的 API 和类:引入了新的 API 和类,如 UnixDomainSocketAddress,以支持 Unix-Domain 套接字的地址表示。

JEP 386:AlpineLinux 移植

Alpine Linux 是一个以安全性和轻量级为特点的 Linux 发行版,广泛用于容器环境,如 Docker。由于它使用 musl-libc 而不是常见的 glibc(GNU C 库),这在过去导致了一些兼容性问题,使得在 Alpine Linux 上运行标准 Java 应用程序变得困难。为了解决这一问题并支持现代云基础设施的发展,Java 需要能够在基于 musl-libc 的系统上原生运行,这就是该特性的主要目标。

JEP 387:弹性元空间

在 Java 8 中,元空间替代了原有的永久代(PermGen),成为存储类元数据的区域。虽然这一改变解决了永久代大小限制的问题,但元空间的内存管理依然不够高效,特别是在类卸载后释放内存方面。Java 16 引入弹性元空间,目的是进一步提高元空间的内存使用效率,特别是在动态加载和卸载类的应用场景中。

主要内容包括:

  1. 更有效的内存回收:在类卸载之后,元空间内存现在可以更快被回收和重用。
  2. 内存占用减少:通过更高效的内存分配策略,减少了元空间的内存占用,特别是在类加载和卸载频繁的场景中。
  3. 内存分配和释放的优化:优化了元空间内部的内存分配和释放机制,提高了性能。

JEP 388:Windows/AArch64 移植

随着 ARM64 架构在个人电脑和服务器市场的逐渐普及,对基于此架构的操作系统的支持变得越来越重要。特别是在 Windows 系统上,随着基于 ARM 的设备的推出,对运行在这些设备上的 Java 应用的需求日益增长。因此,为 Java 提供对 Windows/AArch64 的官方支持,是适应硬件发展趋势和扩大 Java 应用受众的重要步骤。

主要内容包括:

  1. 移植 OpenJDK:对 OpenJDK 进行了必要的修改,以确保它能够在 Windows/AArch64 平台上运行。
  2. 支持 ARM64 特有的特性:包括对 ARM64 架构的特定指令集和优化的支持,以确保 Java 应用在这些设备上能够高效运行。

JEP 389:外部函数与内存 API(孵化器)

Java 一直以来在与本地代码交互方面存在一定的限制,主要通过 JNI(Java Native Interface)来实现。然而,JNI 的使用相对复杂且容易出错,且通常与特定平台紧密相关,这限制了 Java 应用的灵活性和性能。为了解决这些问题,提供更加简洁和安全的本地代码互操作方式,Java 16 引入了外部链接器 API,旨在简化 Java 和本地代码之间的交互操作。

主要是通过两个组件实现的:

  1. Foreign Function Interface (FFI): 允许 Java 代码直接调用非 Java 代码,特别是用 C/C++ 编写的代码。这可以通过定义一种类型安全的方式来实现,同时避免了 Java 本地接口(JNI)的复杂性和开销。
  2. Foreign Memory Access API:提供了一种安全的方法来访问不受 JVM 管理的内存。这对于需要操作系统级别内存操作或者直接与外部设备交互的应用程序非常重要。

该特性的引入带来了如下几个好处:

  • 简化本地代码集成:使得集成本地库变得更加容易和直观,降低了开发难度。
  • 提高性能:提供了一种更高效的方式来访问本地代码,可以提高应用程序的性能。
  • 增强安全性:与 JNI 相比,外部链接器 API 在设计上更注重安全性,减少了安全漏洞的风险。

但是,它目前还处于孵化阶段。

Java 版本 更新类型 JEP 更新内容
Java 14 孵化器 JEP 370 引入了外部内存访问 API
Java 15 第二孵化器 JEP 383 优化外部内存访问 API
Java 16 孵化器 JEP 389 引入了外部链接器 API
Java 16 第三孵化器 JEP 393 继续优化

JEP 390:对基于值的类发出警告

Java 9注解@Deprecated得到了增强,增加了 since 和 forRemoval 两个属性,可以分别指定一个程序元素被废弃的版本,以及是否会在今后的版本中被删除。Java 16 对@jdk.internal.ValueBased注解加入了基于值的类的告警,所以继续在 Synchronized 同步块中使用值类型,将会在编译期和运行期产生警告,甚至是异常。

Java 16 引入该特性的主要目的是警告开发者关于基于值的类的使用。基于值的类是一种特殊类型的类,它们的实例是不可变的,并且不应该有身份。也就是说,它们的实例的行为表现就像是纯粹的数据载体,不应该被视为具有独特身份的实体。

当我们尝试进行同步(使用synchronized关键字)或者使用==比较基于值的类的实例时,编译器会发出警告,比如:

    public void inc(Integer count) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                synchronized (count) { // 这里会产生编译告警
                    count++;
                }
            }).start();
        }
    }

该特性通过告警的方式,引导开发者更好地理解和利用基于值的类,为未来 Java 版本中可能的优化和特性变化做好准备。

JEP 392:打包工具(正式版)

在 Java 14 之前,Java 应用通常依赖于 JAR 文件来分发和运行,或者需要第三方工具来创建本地应用程序包,Java 14 引入一个新的打包工具,基于 javapackager 的 jpackage,用于打包 Java 应用程序为特定平台的本地安装包。但是在 Java 14 中它是作为一个孵化器模块引入的,Java 16 完成了正式版本的发布。

JEP 393:外部存储器访问 API(第三次孵化)

外部存储器访问 API 是在 Java 14 中首次作为孵化器版本引入,Java 15 第二次作为孵化器版本引入,Java 16 为第三次。本次改进:

  • MemorySegmentMemoryAddress 接口之间更清晰的角色分离
  • 新的 MemoryAccess 接口以在简单情况下减少 VarHandle API 的需求、对共享段的支持,以及能够将段注册到 Cleaner
Java 版本 更新类型 JEP 更新内容
Java 14 孵化器 JEP 370 引入了外部内存访问 API
Java 15 第二孵化器 JEP 383 优化外部内存访问 API
Java 16 孵化器 JEP 389 引入了外部链接器 API
Java 16 第三孵化器 JEP 393 继续优化

JEP 394:instanceof 模式匹配(正式特性)

instanceof 模式匹配是在 Java 14 中作为预览特性引入,Java 15 第二次作为预览特性,最终在 Java 16 中成为正式特性。其主要目的是为了在检查对象类型的同时,将该对象自动转换为特定类型的变量,这样可以减少重复的类型检查和转换代码,使得代码变得更加简洁,逻辑更清晰,增强了可读性和可维护性。

Java 版本 更新类型 JEP 更新内容
Java 14 第一次预览 JEP 305 引入 instanceof 模式匹配为预览特性
Java 15 第二次预览 JEP 375 对其进行了修正和优化
Java 16 正式特性 JEP 394 升级为正式特性

更多阅读:Java 14 新特性—模式匹配的 instanceof

JEP 395:Records (正式特性)

Records 是在 Java 14 中作为预览特性引入,Java 15 第二次预览,最终在 Java 16 中成为正式特性。其主要目的是提供一种更简洁、更安全的数据载体。

**Record 本质上是一个不可变的、透明的数据载体对象。**是一种特殊类型的 Java 类,具有如下几个特点:

  • 不可变性:Record 的实例是不可变的,所有字段都是 final 的。
  • 数据驱动:Record 主要用于封装一组数据,字段在对象构造时通过构造器参数传递并初始化。
  • 简洁性:自动生成所有字段的 getters 方法,这些方法名称与字段名称相同。
  • 透明性:自动实现了 equals()hashCode() toString() 方法,它们基于 Record 的状态,即其字段的值。
Java 版本 更新类型 JEP 更新内容
Java 14 第一次预览 JEP 359 Record Classes 作为预览特性引入
Java 15 第二次预览 JEP 384 进行了细微的改动
Java 16 正式特性 JEP 395 成为正式特性

更多阅读:Java 14 新特性—新增Record 类型

JEP 396:默认强封装 JDK 内部元素

在 Java 16 之前,许多 JDK 内部的类和成员尽管没有正式成为公共 API,但仍然可以被外部代码所访问。从 Java 16 开始,默认情况下,这些内部 API 被强制封装,阻止了对它们的非法访问。这样做可以防止开发者依赖于非稳定的、未经官方支持的内部实现,提高了代码的长期稳定性。

Java 16 明确了哪些是公共 API,哪些是 JDK 内部使用的 API,帮助开发者避免依赖于可能在未来版本中改变的内部实现。鼓励开发者使用稳定且官方支持的公共 API,而不是依赖于内部的、可能随时变更的实现。

但是这样就会带来一个兼容性问题,对于依赖于 JDK 内部 API 的现有代码,这种变更可能导致兼容性问题,这就要求我们重新评估现有的代码并进行相应的调整。

JEP 397:密封类(第二预览)

密封类是在 Java 15 中作为预览特性引入,主要目的是为了限制类的继承情况,密封类可以精确控制类的继承问题,Java 16 第二次作为预览特性引入。

Java 版本 更新类型 JEP 更新内容
Java 15 预览特性 JEP 360 引入了密封类作为预览特性。
Java 16 第二次预览 JEP 397

更多阅读:Java 15 新特性—密封类和接口

阅读全文
  • 点赞