3. JDK10 新特性
86: Local-Variable Type Inference 局部变量类型推断
296: Consolidate the JDK Forest into a Single Repository JDK库的合并
304: Garbage-Collector Interface 统一的垃圾回收接口
307: Parallel Full GC for G1 为G1提供并行的Full GC
310: Application Class-Data Sharing 应用程序类数据(AppCDS)共享
312: Thread-Local Handshakes ThreadLocal握手交互
313: Remove the Native-Header Generation Tool (javah) 移除JDK中附带的javah工具
314: Additional Unicode Language-Tag Extensions 使用附加的Unicode语言标记扩展
316: Heap Allocation on Alternative Memory Devices 能将堆内存占用分配给用户指定的备用内存设备
317: Experimental Java-Based JIT Compiler 使用基于Java的JIT编译器
319: Root Certificates 根证书
322: Time-Based Release Versioning 基于时间的发布版本
3.1 局部变量类型推断
JDK 10 引入了局部变量类型推断,通过使用 var
关键字,可以让编译器根据上下文自动推断局部变量的类型。这个特性可以使代码更加简洁和易读。 下面是一个示例:
var str = "Hello, World!"; // 推断为 String 类型
var list = new ArrayList<String>(); // 推断为 ArrayList<String> 类型
在上面的代码中,var
关键字用于声明局部变量 str
和 list
,编译器根据右侧的表达式自动推断变量的类型为 String
和 ArrayList<String>
。 需要注意的是,局部变量类型推断只能用于局部变量的声明和初始化,不能用于方法的参数、方法的返回类型、类的字段等。并且推断的类型是在编译时确定的,运行时变量的类型仍然是具体的类型,这个特性并不会影响 Java 的静态类型检查。 局部变量类型推断可以简化代码书写,特别是在使用泛型、匿名类和复杂类型时能够减少冗余的类型声明。然而,为了保持代码的可读性和清晰性,建议在使用 var
关键字时仍然给变量赋予有意义的名称。 请注意,这个特性是在 JDK 10 中引入的,如果你使用的是更早的 JDK 版本,将无法使用局部变量类型推断。
3.2 引入并行 Full GC算法
- G1 是设计来作为一种低延时的垃圾回收器。G1收集器还可以进行非常精确地对停顿进行控制。从JDK7开始启用G1垃圾回收器,在JDK9中G1成为默认垃圾回收策略。截止到ava 9,G1的Full GC采用的是单线程算法。也就是说G1在发生Full GC时会严重影响性能。
- JDK10又对G1进行了提升,G1 引入并行 Full GC算法,在发生Full GC时可以使用多个线程进行并行回收。能为用户提供更好的体验。
3.3 应用程序类数据共享
应用程序类数据共享(Application Class-Data Sharing)是 JDK 10 引入的一项特性,它旨在改善 Java 应用程序的启动性能和内存占用。 在传统的 Java 应用程序中,每次启动都需要加载和解析大量的类文件,这会消耗较多的时间和内存资源。应用程序类数据共享通过将类元数据和字节码预先计算和存储在共享的存档文件中,使得多个 Java 进程可以共享这些数据,从而减少了类加载和解析的时间和内存开销。 具体来说,应用程序类数据共享包括以下步骤:
- 构建共享的类数据存档(Shared Class-Data Archive,CDS):使用
java -Xshare:dump
命令构建共享的类数据存档。这个命令会启动应用程序,执行一些预热操作,然后生成一个包含类元数据和字节码的存档文件。 - 启用应用程序类数据共享:使用
java -Xshare:on
命令启用应用程序类数据共享。在启用后,Java 进程将使用共享的类数据存档,从而减少类加载和解析的时间和内存占用。
通过应用程序类数据共享,可以显著缩短 Java 应用程序的启动时间和减少内存占用,尤其对于较大的应用程序或需要频繁启动的场景更为有效。 需要注意的是,应用程序类数据共享仅适用于具有相同类路径和相同类加载器结构的 Java 进程。因此,它主要适用于服务器端的 Java 应用程序,而对于客户端或桌面应用程序可能不太适用。 此外,应用程序类数据共享是 JDK 中的商业特性(Commercial Feature),只在 Oracle JDK 和 Oracle OpenJDK 中可用。在其他发行版或替代的 JDK 实现中,可能没有该特性或有所不同的实现方式。
3.4 线程本地握手
- Safepoint是Hotspot JVM中一种让应用程序所有线程停止的机制。为了要做一些非常之安全的事情,需要让所有线程都停下来它才好做。比如菜市场,人来人往,有人忽然要清点人数,这时候,最好就是大家都原地不动,这样也好统计。Safepoint起到的就是这样一个作用。
- JVM会设置一个全局的状态值。应用线程去观察这个值,一旦发现JVM把此值设置为了“大家都停下来”。此时每个应用线程就会得到这个通知,然后各自选择一个point(点)停了下来。这个点就叫Safepoint。待所有的应用线程都停下来了。
- JVM就开始做一些安全级别非常高的事情了,比如下面这些事情:垃圾清理暂停。类的热更新。偏向锁的取消。各种debug操作。
- 然而,让所有线程都到就近的safepoint停下来本是需要较长的时间。而且让所有线程都停下来显得有些粗暴。为此Java10就引入了一种可以不用stop all threads的方式,就是Thread Local Handshake(线程本地握手)。该新特性的效果线程本地握手是在 JVM 内部相当低级别的更改,修改安全点机制,允许在不运行全局虚拟机安全点的情况下实现线程回调,使得部分回调操作只需要停掉单个线程,而不是停止所有线程。
3.5 JDK库的合并
JDK 10 引入了一项名为 "JDK 库的合并"(Consolidate the JDK Forest into a Single Repository)的重要特性。在此之前,JDK 的源代码分布在多个 Mercurial 代码仓库中,而 JDK 10 将这些代码仓库合并为一个单一的 Git 代码仓库。 JDK 库的合并旨在简化 JDK 开发和维护过程,提高开发效率和代码管理的一致性。这项特性将 JDK 代码库从 Mercurial 迁移到 Git,并将所有相关代码合并到一个统一的 Git 仓库中,以便更方便地进行代码的版本控制、分支管理和协作开发。 通过将 JDK 代码库合并为一个 Git 仓库,开发者可以更轻松地浏览和查找 JDK 的源代码,同时更容易参与 JDK 的开发和贡献。此外,这也为社区提供了更便利的方式来提交错误报告、贡献补丁和参与 JDK 开发的讨论。 JDK 库的合并是 JDK 10 中一个重要的基础设施变更,对于 JDK 的开发者和维护者来说具有重要的影响。这项特性的引入标志着 JDK 开发过程中的一项重要改进,并为未来的 JDK 版本提供了更灵活和高效的开发基础。 请注意,以上信息基于 JDK 10 的版本。在更高版本的 JDK 中,可能会有一些变化和进一步的改进。建议查阅官方文档或相关资源以获取最新的信息和详细的说明。
3.6 实验型的垃圾回收接口
JDK 10 的主要特性之一是引入了一种实验性的垃圾回收器接口,称为 "GC 接口"(GC Interface)。该接口的目标是提供一种标准化的方式,使得开发者可以更方便地实现自定义的垃圾回收器。 GC 接口允许开发者基于 JDK 的垃圾回收框架构建自定义的垃圾回收器。通过实现 GC 接口,开发者可以插入自己的垃圾回收算法和策略,并与 JDK 的其他部分进行集成。 然而,需要注意的是,GC 接口在 JDK 10 中仍然是一个实验性的功能,并且不建议在生产环境中使用。这个接口可能在未来的 JDK 版本中进行改进或变化,或者可能被更稳定的替代方案所取代。
3.7 移除JDK中附带的javah工具
这个工具已经被 javac 中的高级功能所取代,这些功能是在 JDK 8(JDK-7150368)中添加的。此功能提供了在编译 Java 源代码时编写本机头文件的能力,从而消除了对单独工具的需求。
3.8 备⽤内存设备上的堆分配
Java 的堆内存通常是分配在主内存中的,并由 JVM 进行管理。备用内存设备(如 SSD、NVMe 等)通常用于存储持久化数据或作为辅助存储设备,而不是用于直接的堆内存分配。 然而,对于大型数据处理、高性能计算等特定场景,可以使用一些特殊的技术和工具,例如使用内存映射文件(Memory-mapped Files)将部分堆内存映射到备用存储设备上,以扩展可用的堆内存空间。这种方法可以提供更大的内存容量,但需要谨慎考虑性能和数据访问的开销。
3.9 基于 Java 的实验性 JIT 编译器
Java 10 引入了一个实验性的 JIT(Just-In-Time)编译器,称为 Graal 编译器。Graal 编译器是基于 Java 实现的,它提供了一种替代 HotSpot JIT 编译器的选择。 Graal 编译器具有以下一些特点和优势:
- 高性能:Graal 编译器通过优化和即时编译技术提供了更好的性能表现,尤其在特定类型的工作负载上可能比 HotSpot JIT 编译器更快。
- 低延迟:Graal 编译器的即时编译能力可以减少应用程序的停顿时间,从而提供更低的延迟和更高的响应性。
- 兼容性:Graal 编译器与现有的 Java 代码和库兼容,并支持在现有的 JVM 环境中使用。
需要注意的是,尽管 Graal 编译器在性能和延迟方面可能带来优势,但它仍然是一个实验性的特性,并且在某些情况下可能与特定的代码或库不兼容。此外,Graal 编译器在编译速度和内存消耗方面可能会有一些权衡,具体取决于应用程序的特点和配置。 为了启用 Graal 编译器,您可以在 JDK 10+ 的启动参数中添加 -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler
。这将激活 Graal 编译器并使用它来编译 Java 代码。
3.10 根证书
JDK 10 中的根证书库与之前的版本类似,仍然包含在 JDK 安装目录下的 "jre/lib/security" 目录中的 "cacerts" 文件中。 根证书库(cacerts)中包含了一系列受信任的根证书,用于验证 SSL/TLS 连接和其他安全通信。这些根证书由各种受信任的证书颁发机构(CA)签发,包括常见的公共 CA 如 VeriSign、Thawte、DigiCert 等。 在 JDK 10 中,根证书库可能会有更新,以反映最新的根证书颁发机构和信任链。由于根证书库的安全性至关重要,因此 Oracle 公司会定期更新 JDK 发布版本中的根证书库,以确保其中包含最新的根证书。 可以使用 JDK 提供的 "keytool" 工具来执行与根证书库相关的操作,例如查看证书、添加新的根证书、删除根证书等。这可以用于管理 JDK 10 中的根证书库,并确保其与最新的证书颁发机构保持同步。 需要注意的是,根证书库的管理需要谨慎操作,确保只信任可靠和受信任的证书颁发机构,并避免操纵根证书库以防止安全风险。