JDK10 揭秘
Posted 程序员阿凯
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK10 揭秘相关的知识,希望对你有一定的参考价值。
前言
Java自1995年发布至今,已经度过23个年头;JAVA也已经推出了10个大的版本,2018年3月20日正式推出JDK10正式版本。新的版本也隐藏了许多新的奥秘,那么本课就将深入浅出的探究一下JDK10新特性。
课程简介
大家都知道开发的核心是JDK,那么每一版新的JDK发布,都标志着Java的进程,Java的前进方向。工欲善其事,必 先利其器。作为老牌军 Java 在发行二十多年的今天,战胜了C 和 C++,成为诸多开发者的宠儿,且如今从其更新速度来看,也是不甘落后。JDK 10 是 Java 10 标准版的部分实现,于 2018 年 3 月 20 日发布,改进的关键点包括一个本地类型推断、一个垃圾回收的“干净”接口。
知识点
新特性之一个局部变量类型推断
新特性之一个干净的垃圾收集器接口新特性之G1 垃圾收集器的优化
新特性之支持备用内存设备
新特性之基于Java实验性的JIT编辑器新特性之应用程序数据共享
新特性之线程本地握手
新特性之基于时间发布的版本控制
新特性之整合源树sourcetree的JDK库
第一章 OpenJDK
1.1简介
Sun 公司在 2006 年的 JavaOne 大会上称将对 Java 开放源代码,于2009年4月15日正式发布 OpenJDK。
OpenJDK做为GPL许可(GPL-licensed)的Java平台的开源化实现.从发布那一时刻起,Java社区的大众们就又开始 努力学习,以适应这个新的开源代码基础(code-base)。OpenJDK在2013年发展迅速,被著名IT杂志SD Times 评选为2013 SD Times 100,位于“极大影响力”分类第9位。在 2015 年年底,Google宣布,他们将 Oracle JavaJDK 替换为了开源的 OpenJDK。
闭源的Oracle JDK和OpenJDK之间并不存在显著的性能差异。但是,我看到 了一个明确的消息(至少是最近), 那就是开源版本总是跟随着Oracle的产品,这可能是开始评估使用开源版本的一个原因。
1.2JDK10 新特性
新的特性和增强一般通过Java Enhancement Process(JEP)或Java Community Process标准请求(JSR)进行跟踪。因为Java 10的时间线较短,范围也相对较小,所以Java 10的变更将通过JEP进行跟踪。
被包含在Java 10中的特性是那些已经处于确定或推荐状态状态的JEP,它们包括(详情页):
286:局部变量类型推断
296:统一JDK仓库
304:垃圾收集器接口
307:G1的并行Full GC
310:应用程序类数据共享
312:线程本地握手
313:移除本地报头生成工具(javah)
314:附加Unicode语言标签扩展
316:替代存储设备上的堆分配
317:基于实验Java的JIT编译器
319:根证书
322:基于时间的版本控制
第二章 下载安装
去官网下载,按步骤安装即可。略......
第三章 局部变量类型推断
3.1概述
每次JDK版本的提升,都会有很多特性出来,对于一般的程序员来讲,可以很直观学习到的就是规范了,比如JDK5中 泛型的出现,提高了程序的灵活性;又比如JDK5中增强for循环,简便了代码的书写,大大提高了开发效率……这些 例子不胜枚举,就不一一赘述了。对于JDK10来讲最为显著的就是引入了局部类型变量推断这个特性。这个特性可 以理解为是JDK8开始可推导可省略的思想的延伸。
在JDK8出现的新特性中加入了函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是
Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中 的Lambda才能顺利地进行推导。
3.2练习:使用Lambda标准格式(有参有返回)
题目
给定一个计算器 Calcuator 接口,内含抽象方法 calc 可以将两个int数字相加得到和值:
1public interface Calculator {
2 int calc(int a, int b);
3}
在下面的代码中,请使用Lambda的标准格式调用 方法,完成120和130的相加计算:
1public class InvokeCalc {
2 public static void main(String[] args) {
3 // TODO 请在此使用Lambda【标准格式】调用invokeCalc方法来计算120+130的结果ß
4 }
5 private static void invokeCalc(int a, int b, Calculator calculator) {
6 int result = calculator.calc(a, b);
7 System.out.println("结果是:" + result);
8 }
9}
解答
1public static void main(String[] args) {
2 invokeCalc(120, 130, (int a, int b) ‐> {return a + b;});
3}
备注:小括号代表 Caluator 接口 calc 抽象方法的参数,大括号代表 calc 的方法体。
3.3Lambda省略格式
可推导即可省略
Lambda强调的是“做什么”而不是“怎么做”,所以凡是可以根据上下文推导得知的信息,都可以省略。例如上例还可 以使用Lambda的省略写法:
1public static void main(String[] args) {
2 invokeCalc(120, 130, (a, b) ‐> a + b);
3}
省略规则
在Lambda标准格式的基础上,使用省略写法的规则为:
1.小括号内参数的类型可以省略;
2.如果小括号内有且仅有一个参,则小括号可以省略;
3.如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
3.3 局部变量类型推断
这一版本最明显的一个新特性就是局部变量类型推导,在OpenJDK JEP 286中有详细的介绍,那么本文就将深入浅出的学习一下新特性的使用方式。
OpenJDK中的 JEP指的是JDK提供了一些更好的特性和高级支持。286: Local-Variable Type Inference
概要:增强Java语言,用来将类型推断扩展到有初始值设定项的局部变量声明。
这种处理方式必须是具有可推导性的,并且具有约束条件的。
其他静态类型语言, 如 C++, Scala, 和 Go,都已经实现了局部变量类型推断。
因为Java仍缺乏这样的功能,它要求开发人员显式声明变量的预期清单类型。为了解决这个问题,Java开发工具包
( JDK)改进建议( JEP)286提出了一个上下文敏感的关键字var,允许局部变量被以下方式初始化。
描述
Java开发人员在开发过程中经常会发现标准样板代码体积臃肿。
也就是说使用变量的时候,用来声明名字重点在于名字起得是什么,重点并不是接收的数据类型。该计划限制了类 型推断的使用场景: 有初始值的局部变量, 增强型for循环中的index, 普通for循环里的局部变量。
由于var关键字是上下文敏感的,它的使用有下面的规则定义:
备注:“语法糖”是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实 底层的实现原理仍然是迭代器,这便是“语法糖”。从应用层面来讲,Java中的Lambda可以被当做是匿名内部 类的“语法糖”,但是二者在原理上是不同的。
它其实是个语法糖,在语义上并没有任何变化。接下来演示一下使用场景:
有初始值的局部变量:
1public static void main(String[] args){
2var itcast = new Student("KK爱Java");// 原型为 Student 类型
3}
增强型for循环中的index:
1public static void main(String[] args){
2 var list = new ArrayList<String>();// 原型为 ArrayList<String> 类型
3 list.add("1");
4 list.add("3");
5 list.add("4");
6 for (var i : list) { //原型为 String 类型
7 System.out.println(i);
8 }
9}
普通for循环里的局部变量:
1public static void main(String[] args){
2 var arr = new String[3];// 原型为 String[]类型
3 arr[0]="小明";
4 arr[1]="小红";
5 arr[2]="小张";
6 for (var i = 0; i < arr.length; i++) {
7 var value = arr[i]; //原型为 String 类型
8 System.out.println(value);
9 }
10}
既然是可推导的,那么作为类型接收同样可以用在有返回值方法接收上,以及有返回值lambda表达式上。
1public class Student {
2 public static void main(String[] args){
3 var sum = sum(2,4);
4 var read = new Thread(()‐> System.out.println("青铜卡了好久了"));
5 }
6 public static int sum(int a ,int b){
7 return a+b;
8 }
9}
第四章 JDK10有趣的特性
4.1整合的JDK库
296:Consolidate the JDK Forest into a Single Repository
统一JDK仓库,目前,JDK9有8个不同的Mercurial存储库用于存储包含JDK的大量源代码:
(1)root,(2)corba,(3)hotspot,(4)jaxp,(5)jaxws,(6)JDK,(7)langtools,(8)nashorn。
虽然过多的存储库提供了对组成JDK的各种组件并清晰分离,但管理多个存储库存在一些主要的缺点。其中最重要 的一点是,在JDK的两个不同部分,单个错误修复程序不能被原子跟踪。例如,如果一个bug修复需要对独立存储 库中包含的系统的两个部分进行更改,那么必须提交两个提交:每个存储库中一个。这种不连续性很容易地降低项目 和源代码管理工具的可跟踪性和复杂性。 为了解决这个问题,JEP 296建议将所有现有存储库合并到一个
Mercurial存储库中。这种合并的一个次生效应是,这个单一的Mercurial存储库比现有的8个存储库要更容易的被 镜像(作为一个Git存储库)。虽然在这个整合过程中,外部开发人员有一些阻力,但是JDK开发团队似乎已经致力于 使这一更改成为JDK 10的一部分。有关更多信息,请参见JEP 296,并提议整合由Michael Redlich发布的JDK 10 OpenJDK Mercurial存储库声明。
简而言之,将 JDK 的多个存储库合并成一个,简化开发。目前的代码库被分解成了多个库,容易出现源代码的管理问题。
—— corba:不流行的多语言、分布式通讯接口
—— hotspot:Java 虚拟机
—— jaxp:XML 处理
—— jaxws:一组 XML web services 的 Java API
—— jdk:java 开发工具包
—— share:针对操作系统的部分 , 与平台无关的实现
—— langtools:Java 语言工具
—— nashorn:JVM 上的 javascript 运行时
4.2应用程序类数据共享
310: Application Class-Data Sharing
应用程序类数据共享,JEP 310对类数据共享(CDS)进行了扩展,JVM可以将一些类记录到一个共享的压缩文件里,在JVM下一次启动时可以将这个文件映射到JVM进程,以此来减少启动时间。该文件也可以在多个JVM间共 享,在同一个机器上运行多个JVM时,这样做可以减少内存占用。
该功能在Java 5中就已存在,但截止到Java 9,该功能只允许bootstrap类加载器加载压缩的类。JEP 310的目的是扩展该功能,让应用程序和自定义类加载器也能加载压缩的类。该特性目前仅在Oracle JDK中可用,OpenJDK并不包含该特性。JEP计划将该特性从Oracle私有仓库中迁移到公共仓库,从Java 10往后,常规版本(非LTS)将会使用OpenJDK的二进制包。此举表明有用户正在使用该特性,所以需要在OpenJDK中也支持该特性。
简而言之,应用程序类数据共享,通过跨进程共享通用类元数据来减少占用空间。启动时间也得到了改善。
4.3常规更新
313: Remove the Native-Header Generation Tool (javah)
去掉 javah 工具。
从 JDK 8 开始,javah 的功能已经集成到了 javac 中。所以,javah 可以删掉了。Java9 开始了一些对 JDK 的家务管理,这项特性是对它的延续。当编译 JNI 代码时,已不再需要单独的工具来生成头文件,因为这可以通过 javac 完成。在未来的某一时刻,JNI 将会被 Panama 项目的结果取代,但是何时发生还不清楚。
314: Additional Unicode Language-Tag Extensions
额外的 Unicode 语言标签扩展。
增强java.util.Locale和相关 API,包括:cu (货币类型)、fw (每周第一天为星期几)、rg (区域覆盖)、tz (时区)等。
316: Heap Allocation on Alternative Memory Devices
在备用内存设备上分配堆内存。
允许 HotSpot 虚拟机在备用内存设备上分配 Java 对象堆。硬件技术在持续进化,现在可以使用与传统 DRAM 具有相同接口和类似性能特点的非易失性 RAM( NV-DIMM) 。这项 JEP 将使得 JVM 能够使用适用于不同类型的存储机制的堆。
317: Experimental Java-Based JIT Compiler
实验性的基于 Java 的 JIT 编译器。
支持基于 Java 的 JIT 编译器。相关工作主要基于 Graal。Graal 也是 Java 9 中引入的 AOT 编译器的基础。乍一想, 觉得很奇怪。如果 JVM 是用 Java 编写的,那么是否需要一个 JVM 来运行 JVM ? 相应的,这导致了一个很好的镜像类比。 现实情况是,使用 Java 编写 JVM 并不意味着必须将其编译为字节码,你可以使用 AOT 编译,然后在运行时编译代码以提高性能。
319: Root Certificates
根证书。
开源 Java SE Root CA 程序中的根证书。目标是开源 Oracle 的 Java SE Root CA 程序中的根证书,以使 OpenJDK 对开发人员更具吸引力。这是 Oracle 正在努力确保 OpenJDK 二进制和 Oracle JDK 二进制功能上一样的工作的一部分,是一项有用的补充内容。
322: Time-Based Release Versioning
基于时间的版本字符串。
修改 Java SE 平台和 JDK 版本字符串机制。
Oracle Java 平台组首席架构师 Mark Reinhold 在博客上介绍了有关 Java 未来版本的一些想法(你能接受Java 9的 下一个版本是Java 18.3吗?)。他提到,Java 计划按照时间来发布,每半年一个版本,而不是像之前那样按照重要特性来确定大版本,如果某个大的特性因故延期,这个版本可能一拖再拖。 当时,Mark 也提出来一种基于时间命名版本号的机制,比如下一个将于 2018 年 3 月发布的版本,就是 18.3,再下一个版本是 18.9,依此类推。 不过经过讨论,考虑和之前版本号的兼容等问题,最终选择的命名机制是: INTERIM.
PATCH $FEATURE,每次版本发布加 1,不考虑具体的版本内容。(之前的主版本号部分)2018 年 3 月的版本是JDK 10,9 月的版本是 JDK 11,依此类推。 $INTERIM,中间版本号,在大版本中间发布的,包含问题修复和增强的版本,不会引入非兼容性修改。
第五章 JVM优化
304: Garbage-Collector Interface
307: Parallel Full GC for G1
312: Thread-Local Handshakes
304: 垃圾收集器接口,在 hotspot/gc 代码实现方面,引入一个干净的垃圾收集器接口,改进不同垃圾收集器源代码的隔离性。这样添加新的或者删除旧的 GC,都会更容易。
可以这样理解,增加GC接口意味着厂商可以更自由地选择特定的GC算法来构建JDK,因为现在有多种处于开发当 中的GC,如Shenandoah、ZGC和Epsilon,在未来可以使用这些GC算法。这样做是为了更好地模块化 HotSpot 虚拟机中的内部垃圾回收代码,使向 HotSpot 添加新的垃圾回收器更加容易。
307: G1的并行Full GC,从JDK8开始启用G1,在JDK9中移除JDK8中废除的GC组合,在32/64位服务器版配置中,
G1成为默认垃圾回收策略。使用低停顿时长的垃圾回收器如G1相较之前默认的流量优先的回收器如Parellel GC, 能为大部分用户提供更好的体验。改进G1可用性、决策和性能,弃用CMS垃圾回收器。
当在命令行指定 - XX:+UseConcMarkSweepGC时会有警告信息。G1垃圾回收器会取代大部分CMS的使用场景。
JDK10又对G1进行了提升,而且还有加入人体工学的设想(这个版本并没有),为了减少JDK 9之外的JDK版本中垃圾收集的影响,G1收集器将被并行化(以匹配并行收集器的特征)。虽然目前还没有关于这个并行化的实现细节的信息,但是可以在JEP 307规范中找到关于此更改的更多细节。有关GC实现的更多信息,请参阅Oracle的G1指南和并行收集器指南。简 单理解,解决了G1垃圾回收器的一个问题——截止到Java 9,G1的Full GC采用的是单线程算法。也就是说,G1在发生Full GC时会严重影响性能。JEP 307的目的就是要采用并行GC算法,在发生Full GC时可以使用多个线程进行 并行回收。
312: 线程本地握手,修改安全点机制,使得部分回调操作只需要停掉单个线程,而不像以前那样,只能选择或者停掉所有线程,或者都不停止。
旨在改进虚拟机性能,在应用程序线程上调用回调不再需要执行全局虚拟机安全点操作,这意味着JVM可以停止单 个线程。一些底层小改进包括:
降低堆栈跟踪取样所带来的影响(如进行profiling)。减少信号依赖以获得更好的堆栈取样。
通过停止单独线程改进偏向锁。从JVM移除了一些内存屏障。
“局部变量的类型推断”可以说是这 12 个 JEP 中最受关注的,为支持此特性,开发团队也对 Java 语言规范做了一些更改,包括改变具有相同名称的静态类型的导入规则、将 var 作为局部变量类型推断的特殊标识符等等。
此外还包括新增的 73 个标准类库,对 JVM 规范的更改,以及一些其他更改项。
第六章 新API
有 73 项新增内容添加到了标准类库中。
java.awt.Toolkitint getMenuShortcutKeyMaskEx(): 确定哪个扩展修饰符键是菜单快捷键的适当加速键。
java.awt.geom.Path2D:
void trimToSize(): 将此 Path2D 实例的容量计算到它当前的大小。应用可使用此操作将路径的存储空间最小化。这个方法也被添加到 Path2D.Double 和 Path2D.Float 类。
java.io.ByteArrayOutputStream:String toString(Charset): 重载 toString(),通过使用指定的字符集解码字节,将缓冲区的内容转换为字符串。
java**.io.PrintStream:lang.io.PrintWriter:**
这两个类都有三个新的构造函数,它们需要额外的 Charset 参数。
java.io.Reader:long transferTo(Writer): 从这个 Reader 中读取所有字符,并按照所读的顺序将字符写入给定的 Writer 。
java.lang.Runtime.Version:
有四种新方法返回新(JEP 322)版本字符串字段的整数值: feature()、interim()、patch() 和 update() 。
java.lang.StackWalker.StackFrame:
String getDescriptor(): 按照 JVM 标准返回此堆栈帧所代表的方法的描述符。
String getMethodType():返回此堆栈帧所代表的方法类型,描述参数类型和返回值类型。java.lang.invoke.MethodType:Class<?> lastParameterType():返回这个方法类型的最后一个参数类型。如果这个方法类型没有参数,则返回空类型作为岗哨值(Sentinel Value)。java.lang.management.RuntimeMXBean:long getPid(): R 返回正在运行的 JVM 的进程 ID 。java.lang.management.ThreadMXBean:ThreadInfo[] dumpAllThreads(boolean, boolean, int): 返回所有活动线程的线程信息,其中有指定的最大元素数量和同步信息的堆栈跟踪。
ThreadInfo[] getThreadInfo(long[], boolean, boolean, int): 返回每个线程的线程信息,这些线程的标识位于输入数组中,其中有指定的最大元素数量和同步信息的堆栈跟踪。
java.lang.reflect.MalformedParameterizedTypeException: 添加了一个新的构造函数,它以字符串的形式作为参数来获取详细信息。
java.net.URLDecoder:java.net.URLEncoder:
java.nio.channels.Channels:
两个新的静态重载方法,允许使用 Charset 的 newReader(ReadByteChannel,Charset)和
newWriter(WriteByteChannel,Charset)。
java.nio.file.FileStore:long getBlockSize(): 在这个文件存储中返回每个块的字节数。
java.time.chrono: 这个包里有三个类,HijrahEra、MiinguoEra 和 ThaiBuddhistEra ,都有同样的方法。
String getDisplayName(TextStyle, Locale): 这将返回用于识别 era 的文本名称,适合于向用户展示。
java.time.format.DateTimeFormatter:localizedBy(Locale): 返回指定格式器的一个副本,其中包含地区、日历、区域、小数和/或时区的本地化值,这将取代该格式器中的值。
java.util: DoubleSummaryStatistics、IntSummaryStatistics 和 LongSummaryStatistics 都有一个新的构造函数,它包含 4 个数值。它使用指定的计数、最小值、最大值和总和构造一个非空实例。
java.util.List:java.util.Map:java.util.Set: 这些接口中的每一个都增加了一个新的静态方法,
copyOf(Collection)。这些函数按照其迭代顺序返回一个不可修改的列表、映射或包含给定集合的元素的集 合。
java.util.Optional:java.util.OptionalDouble:java.util.OptionalInt:java.util.OptionalLong: 每 一 个 类都有一个新的方法,orElseThrow() ,它本质上和 get() 一样,也就是说,如果 Optional 有值则返回。否则, 将抛出 NoSuchElementException 。
java.util.Formatter: java.util.Scanner:
这两个类都有三个新的构造函数,除了其他参数之外,它们都带有一个 charset 参数。
java.util.Properties: 这有一个新的构造函数,它接受一个 int 参数。这将创建一个没有默认值的空属性列表,并且指定初始大小以容纳指定的元素数量,而无需动态调整大小。还有一个新的重载的 replace 方法,接受三个 Object 参数并返回一个布尔值。只有在当前映射到指定值时,才会替换指定键的条目。java.SplittableRandom:
void nextBytes(byte[]): 用生成的伪随机字节填充一个用户提供的字节数组。
java.util.concurrent.FutureTask: 添加了 toString() 方法,该方法返回一个标识 FutureTask 的字符串,以及它的完成状态。在括号中,状态包含如下字符串中的一个,“Completed Normally” 、“Completed
Exceptionally”、 “Cancelled” 或者 “Not completed”。java.util.concurrent.locks.StampedLock:
boolean isLockStamp(long): 返回一个标记戳表示是否持有一个锁。
boolean isOptimisticReadStamp(long): 返回一个标记戳代表是否成功的进行了乐观读(optimistic
read)。
boolean isReadLockStamp(long): 返回一个标记戳表示是否持有一个非独占锁(即 read lock )。
boolean isWriteLockStamp(long): 返回一个标记戳表示是否持有一个独占锁(即 write lock )。
java.jar.JarEntry:
String getRealName(): 返回这个 JarEntry 的真实名称。如果这个 JarEntry 是一个多版本 jar 文件的入口, 它被配置为这样处理,这个方法返回的名字是 JarEntry 所代表的版本条目的入口,而不是
ZipEntry.getName() 返回的基本条目的路径名。如果 JarEntry 不代表一个多版本 jar 文件的版本化条目或者 jar 文件没有被配置为作为一个多版本 jar 文件进行处理,这个方法将返回与 ZipEntry.getName() 返回的相同名称。
java.util.jar.JarFile:
Stream versionedStream(): 返回 jar 文件中指定版本的入口对应 Stream 。与 JarEntry 的 getRealName 方法类似,这与多版本 jar 文件有关。java.util.spi.LocaleNameProvider:getDisplayUnicodeExtensionKey(String, Locale): 为给定的
Unicode 扩展键返回一个本地化名称。
getDisplayUnicodeExtensionType(String, String, Locale): 为给定的 Unicode 扩展键返回一个本地化名称 。 java.util.stream.Collectors:toUnmodifiableList():toUnmodifiableSet():toUnmodifiableMap(Functi on, Function):
toUnmodifiableMap(Function, Function, BinaryOperator): 这四个新方法都返回 Collectors ,将输入元素聚集到适当的不可修改的集合中。
java.lang.model.SourceVersion: 现在有了一个字段,它代表了 JDK 10 的版本。java.lang.model.util.TypeKindVisitor6: javax.lang.model.util.TypeKindVisitor9:
(我必须承认,我从来没听说过这些类)
R visitNoTypeAsModule(NoType, P): 访问一个 MODULE 的 pseudo-type 。我不确定为什么只有这两个类得到这个方法,因为还有 Visitor7 和 Visitor8 变量。javax.remote.management.rmi.RMIConnectorServer:
这个类已经添加了两个字段: CREDENTIALS_FILTER_PATTERN 和 SERIAL_FILTER_PATTERN 。
javax.ButtonModel:看,Swing 还在更新!
ButtonGroup getGroup(): 返回按钮所属的组。通常用于单选按钮,它们在组中是互斥的。
javax.plaf.basic.BasicMenuUI:
Dimension getMinimumSize(JComponent): 返回指定组件适合观感的最小大小。
从整体来看,Java 10似乎并没有包含重大新特性或性能改进。这是可以理解的,毕竟这是新发布周期下的第一个版本。
如上所述,尽管距离 JDK 9 发布仅有六个月的时间,但 JDK 10 实际上有相当多的变化。当然,它们中的一些是非常小的变更,但我认为这表明目前每 6 个月发布一次的节奏,将在 Java 平台快速迭代改进方面起到作用。
同时也让我们期待 JDK 11 将带来些什么…
JDK 11 的页面已经出现了四个 JEP ,包括:动态类文件常量(JEP 309,Dynamic Class-File Constants)、低开销垃圾收集器 Epsilon(JEP 318)、移除 Java EE 和 CORBA 模块(JEP 320),以及 Lambda 参数的本地变量语法
(JEP 323)。JDK 11 计划于 2018 年 9 月发布,并有望成为新的 LTS 版本。
以上是关于JDK10 揭秘的主要内容,如果未能解决你的问题,请参考以下文章
拼多多探究Java并发底层原理JDK源码解析大揭秘,由浅入深看源码