本篇文章为你整理了升级指南之JDK 11+ 新特性和AJDK(jdk11的新特性有哪些)的详细内容,包含有jdk1. 8新特性 jdk11的新特性有哪些 jdk1.5新特性 jdk1.7新特性 升级指南之JDK 11+ 新特性和AJDK,希望能帮助你了解 升级指南之JDK 11+ 新特性和AJDK。
JDK已经如火如荼的更新到了JDK 19,集团内也在推AJDK 11的升级,升级已然是一个大趋势。本文主要是对体育营销场景升级JDK 11,进行了整理与总结,希望对大家有所帮助。
写在前面:
JDK已经如火如荼的更新到了JDK 19,集团内也在推AJDK 11的升级,升级已然是一个大趋势。本文主要是对体育营销场景升级JDK 11,进行了整理与总结,希望对大家有所帮助。
从1996年初JDK1.0发布到现在已经二十多年了, 最新一个版本已经到 JDK 19,JDK17是最新的一个LTS(Long-Term Support)版本。所谓LTS版本就是可以得到至少八年产品支持的版本。到目前为止,有四个LTS版本,JDK 7、JDK 8、JDK 11、JDK 17,下一个LTS版本是JDK 21,预计在2023年9月发布。Oracle 每隔6个月就会有一个短期维护版本(non-LTS)发布出来;然后每隔2年,就会发布一款得到8年长期支持维护的JDK版本,下图是oracle官方发布的roadmap, 可以更直观的看到JDK版本的更新, 这个发布节奏着实让人有点追不上啊。
上图显示了自 Java 8 起到 Java 19 各版本新增特性的数量。从 Java 8 到 Java 19 总共引入了超过 250 个新特性,其中 Java 9 中包含了 91 个新特性,这是由于之前的发布周期较长所导致的,在应用新的发布模型后,各版本的新增特性数量都维持在 10 个左右的水平。下面主要针对各版本的主要特性进行介绍
模块化提供了比 package 更高级别的聚合,模块是一个包的容器。模块的代码被组织成多个包,每个包中包含Java类和接口;如果我们想让项目成为一个模块,则需要在该项目的java源码的根目录(如果是maven项目也就是src/main/java)添加一个特殊的java文件模块描述符文件 module-info.java,以jdk 里java.sql 模块为例:
/**
* Defines the JDBC API.
* @uses java.sql.Driver
* @moduleGraph
* @since 9
// 声明模块
module java.sql {
// 声明依赖模块, transitive修饰符会导致依赖于当前模块的其他模块具有隐式依赖性。
requires transitive java.logging;
requires transitive java.transaction.xa;
requires transitive java.xml;
// 声明哪些包是可以被其它模块访问
exports java.sql;
exports javax.sql;
// 使用语句(uses statement)和提供语句(provides statement)实现其服务
// 使用语句可以指定服务接口的名字,当前模块就会发现它,使用 java.util.ServiceLoader类进行加载
uses java.sql.Driver;
}
接口支持私有方法
JDK 8 为我们带来了接口的默认方法。接口现在也可以包含行为,而不仅仅是方法签名。JDK 9支持了私有方法,可以解决接口中代码复用问题;该特性主要是为了Java 8中default方法和static方法服务的。
public interface TestInterface{
default void method(){ init(); }
default void anotherMethod(){ init(); }
private void init(){ System.out.println("Initializing");}
}
新增Stream API 集合工厂方法
JDK 9 为 Stream 新增了几个方法:dropWhile、takeWhile、ofNullable,为 iterate 方法新增了一个重载方法。
takeWhile 方法使用一个断言作为参数,返回给定 Stream 的子集直到断言语句第一次返回 false。如果第一个值不满足断言条件,将返回一个空的 Stream。
// 输出 = abc
Stream.of("a","b","c","","e","f").takeWhile(s- !s.isEmpty())
.forEach(System.out::print);
dropWhile 方法和 takeWhile 作用相反的,使用一个断言作为参数,直到断言语句第一次返回 true 才返回给定 Stream 的子集。
// 输出 = ef
Stream.of("a","b","c","","e","f").dropWhile(s- !s.isEmpty())
.forEach(System.out::print);
// 通过k1,v1,k2,v2,...,形式创建
Map String, String map = Map.of("A","V1","B","v2","C","v3");
// 通过 Map.entry 形式创建
Map Integer, String map1 = Map.ofEntries (
Map.entry(1, "v1"),
Map.entry(2, "v2"),
Map.entry(3, "v3"));
改进版 Try-With Resources
try-with-resources 是 JDK 7 中一个新的异常处理机制,它能够很容易地关闭在 try-catch 语句块中使用的资源。try-with-resources 声明在 JDK 9 已得到改进。如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。
static String readData(String message) throws IOException {
Reader reader = new StringReader(message);
BufferedReader br = new BufferedReader(reader);
// 不需要重新声明变量
try (br) {
return br.readLine();
}
G1 成为默认垃圾收集器
在 Java 8 的时候,默认垃圾回收器是 Parallel Scavenge(新生代)+Parallel Old(老年代)。到了 Java 9, CMS 垃圾回收器被废弃了,G1(Garbage-First Garbage Collector) 成为了默认垃圾回收器。G1 是在 Java 7 中被引入的,经过两个版本优异的表现成为成为默认垃圾回收器。
APPCDS 应用程序类数据共享
CDS 的全称是 Class-Data Sharing, CDS 的作用是让类可以被预处理放到一个归档文件中,后续 Java 程序启动的时候可以直接带上这个归档文件,这样 JVM 可以直接将这个归档文件映射到内存中,以节约应用启动的时间。这个特性在 JDK 1.5 就开始引入, 但是 CDS 只能作用与 Boot Class Loader 加载的类,不能作用于 App Class Loader 或者自定义的 Class Loader 加载的类。在 JDK 10 中, CDS 扩展为 AppCDS,AppCDS 不止能够作用于 Boot Class Loader,App Class Loader 和自定义的 Class Loader 也都能够起作用,进一步提高了应用启动性能。
多线程并行 GC
在JDK9中G1被选定为默认的垃圾收集器,G1的设计目标是避免发生Full GC,由于Full GC较难产生所以在设计之初只有Young GC和Mixed GC是并行的,而Full GC是单线程使用标记-清理-合并算法进行垃圾回收。G1只是避免发生Full GC,在极端情况下,当G1的回收速度相对于产生垃圾的速度不是足够快时,就会发生Full GC。
为了最大限度地减少 Full GC 造成的应用停顿的影响,从 JDK 10开始,G1 的 FullGC 改为并行的标记清除算法,同时会使用与年轻代回收和混合回收相同的并行工作线程数量,从而减少了 Full GC 的发生,以带来更好的性能提升、更大的吞吐量
线程的数量可以由-XX:ParallelGCThreads选项来控制,这个参数也用来控制Young GC和Mixed GC的线程数。
局部变量类型推断
JDK10 可以使用var作为局部变量类型推断标识符,此符号仅适用于局部变量,增强for循环的索引,以及传统for循环的本地变量;它不能使用于方法形式参数,构造函数形式参数,方法返回类型,字段,catch形式参数或任何其他类型的变量声明。
var list = new ArrayList String
list.add("hello,world!");
System.out.println(list);
反编译后是这样的
ArrayList String list = new ArrayList();
list.add("hello,world!");
System.out.println(list);
从示例中可以看出,var 其实是一种语法糖,旨在改善开发者体验
线程-局部管控
这是在 JVM 内部相当低级别的更改,现在将允许在不运行全局虚拟机安全点的情况下实现线程回调。这将使得停止单个线程变得可能和便宜,而不是只能启用或停止所有线程。
基于Java的实验性JIT编译器Graal
Graal 是一个以 Java 为主要编程语言,面向 Java bytecode 的编译器。与用 C++ 实现的 C1 及 C2 相比,它的模块化更加明显,也更加容易维护。Graal 既可以作为动态编译器,在运行时编译热点方法;亦可以作为静态编译器,实现 AOT 编译。在 JDK 10 中,Graal 作为试验性 JIT compiler 一同发布
支持TLS 1.3 协议
实现TLS协议1.3版本, 替换了之前版本中包含的 TLS,包括 TLS 1.2,同时还改进了其他 TLS 功能, 在安全性和性能方面也做了很多提升
HTTP Client
在 JDK 11 中 Http Client API 得到了标准化的支持。且支持 HTTP/1.1 和 HTTP/2 ,也支持 websockets。
使用起来也很简单,如下:
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.build();
// 异步
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
// 同步
HttpResponse String response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Epsilon:低开销垃圾回收器
新增的垃圾回收器,一个完全消极的 GC 实现,分配有限的内存资源,最大限度的降低内存占用和内存吞吐延迟时间
飞行记录器:JFR
Java飞行记录器(Java Flight Recorder)已经变成JDK 11的一部分了,之前它是一个商业功能,但是伴随JDK 11发布,它从OracleJDK开源到了OpenJDK。
飞行记录器类似飞机上的黑盒子,是一种低开销的事件信息收集框架,主要用于对应用程序和 JVM 进行故障检查、分析。飞行记录器记录的主要数据源于应用程序、JVM 和 OS,这些事件信息保存在单独的事件记录文件中,故障发生后,能够从事件记录文件中提取出有用信息对故障进行分析
可中止的混合收集集合:为了达到用户提供的停顿时间目标,通过把要被回收的区域集(混合收集集合)拆分为强制和可选部分,使 G1 垃圾回收器能中止垃圾回收过程。G1 可以中止可选部分的回收以达到停顿时间目标。
及时返回未使用的已分配内存:由于 G1 尽量避免完整的 GC,并且仅基于 Java 堆占用和分配活动来触发并发周期,因此在许多情况下,除非从外部强制执行,否则它不会返还 Java 堆内存。JDK 12增强了 G1 GC,可以在空闲时自动将 Java 堆内存返回给操作系统。
SocketAPI 重构
java.net.Socket和java.net.ServerSocket类早在 Java 1.0 时就已经引入了,它们的实现的 Java 代码和 C 语言代码的混合,维护和调试都十分不易;而且这个实现还存在并发问题,有时候排查起来也很困难。JDK 13 将 Socket API 的底层进行了重写,并且在 JDK 13 中是默认使用新的 Socket 实现, 使其易于排查问题,同时也增加了可维护性。
动态 CDS 存档
JDK 13 中对 JDK 10 中引入的应用程序类数据共享(AppCDS)进行了进一步的简化、改进和扩展,即:允许在 Java 应用程序执行结束时动态进行类归档,具体能够被归档的类包括所有已被加载,但不属于默认基层 CDS 的应用程序类和引用类库中的类。这提高了应用程序类数据共享AppCDS的可用性。
增强 switch
增强版 switch 在 JDK 12 作为预览特性引入。在 JDK 14 之后,增强版 switch 语句块具备返回值
String result = switch (day) {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" - "工作日";
case "weekend" - "周末";
default - {
// yield 关键字 yield的是JDK13后的一个新特性,它主要的作用是进行程序的局部返回
yield "unknown";
System.out.println(result);
移除 CMS 垃圾收集器
移除了 CMS(Concurrent Mark Sweep) 垃圾收集器(功成而退)
JDK 15正式发布文本块功能, 用来解决多行文本的问题,文本块以三重双引号开头,并以同样的以三重双引号结尾终止
String content = """
JDK 10
JDK 11
JDK 12
""";
System.out.println(content);
JDK 10
JDK 11
JDK 12
Hidden Classes(隐藏类)
此功能可帮助需要在运行时生成类的框架。框架生成类需要动态扩展其行为,但是又希望限制对这些类的访问。隐藏类很有用,因为它们只能通过反射访问,而不能从普通字节码访问。此外,隐藏类可以独立于其他类加载,这可以减少框架的内存占用。
instanceof 模式匹配
之前使用instanceof 进行类型判断之后,需要进行对象类型转换后才能使用。而在 JDK 16 中,可以在判断类型时指定变量名称进行类型转换,方便了使用。
// JDK 16之前
if (obj instanceof String) {
// 强制转换后使用
String str = (String)o;
... use str ...
// JDK 16
if (o instanceof String str) {
// 直接使用str变量
... use s ...
}
record 是一种全新的类型,它本质上是一个 final 类,同时所有的属性都是 final 修饰,或者可看成是 Lombok 中 @Data 注解的一个 "低配" 替代。它会自动编译出 getXXX、toString、 hashcode 、equals等方法,减少了代码编写量。
// 定义记录类
public record Person(String name, Integer age) {
// ======
// 使用
Person person = new Person("张三", 16);
System.out.println(person);
ZGC 并发线程堆栈处理
ZGC是JDK 11引入的新的垃圾收集器,JDK 15 正式发布成正式特性,ZGC是一个重新设计的并发的垃圾回收器,可以极大的提升GC的性能。支持任意堆大小而保持稳定的低延迟(10ms以内),性能非常可观。
JDK 16将 ZGC 线程栈处理从安全点转移到一个并发阶段,甚至在大堆上也允许在毫秒内暂停 GC 安全点。消除 ZGC 垃圾收集器中最后一个延迟源可以极大地提高应用程序的性能和效率。
增强的伪随机数生成器
JDK 17 之前,我们可以借助 Random、ThreadLocalRandom和SplittableRandom来生成随机数。不过,这 3 个类都各有缺陷,且缺少常见的伪随机算法支持。
JDK 17 为伪随机数生成器 (pseudorandom number generator,RPNG,又称为确定性随机位生成器)增加了新的接口类型和实现,使得开发者更容易在应用程序中互换使用各种 PRNG 算法。
使用示例:
RandomGeneratorFactory RandomGenerator l128X256MixRandom = RandomGeneratorFactory.of("L128X256MixRandom");
// 使用时间戳作为随机数种子
RandomGenerator randomGenerator = l128X256MixRandom.create(System.currentTimeMillis());
// 生成随机数
randomGenerator.nextInt(10));
密封类可以是封闭类和或者封闭接口,用来增强 Java 编程语言,防止其他类或接口扩展或实现它们。这个特性由JDK 15的预览版本在JDK 17晋升为正式版本。
密封类引入了sealedclass或interface,这些class或者interfaces只允许被指定的类或者interface进行扩展和实现。使用修饰符sealed,可以将一个类声明为密封类。密封的类使用关键字permits列出可以直接扩展它的类。子类可以是最终的,非密封的或密封的。
// 比如现在要限制 Person类 只能被这三个类继承,不能被其他类继承,可以这么做
// 添加sealed修饰符,permits后面跟上只能被继承的子类名称
public sealed class Person permits Teacher, Worker, Student{ } //人
// 子类可以被修饰为 final
final class Teacher extends Person { }//教师
// 子类可以被修饰为 non-sealed,此时 Worker类就成了普通类,谁都可以继承它
non-sealed class Worker extends Person { } //工人
// 任何类都可以继承Worker
class AnyClass extends Worker{}
移除实验性的 AOT 和 JIT 编译器
实验性的基于 Java 的提前 (AOT) 和即时 (JIT) 编译器是实验性功能,并未得到广泛采用。作为可选,它们已经从 JDK 16 中删除。这个 JEP 从 JDK 源代码中删除了这些组件。
删除 Applet API
Applet 是使用 Java 编写的可以嵌入到 HTML 中的小应用程序,嵌入方式是通过普通的 HTML 标记语法,由于早已过时,几乎没有场景在使用了。Applet API 在 JDK 9 时已经标记了废弃,现在 JDK 17 中彻底删除
AJDK是集团JVM 团队在 Java Standard Edition (SE) 规范下的 OpenJDK 基础上自主研发的 JDK 版本,开源版本是Alibaba Dragonwell
应用启动加速EagerAppCDS
针对阿里的应用场景,对AppCDS进行优化, 缩短应用启动时间
代码预热技术JWarmup2
JWarmup是AJDK 8引入的一个功能,主要是解决线上应用代码预热的问题,JWarmup2在JWarmup1基础上开发,使用更便捷,性能更优。
AppAOT
AOT(ahead of time)是一项新的Java编译技术,不同于我们习惯的Jit(Just in time)编译,AOT在应用运行前就把一部分代码编译好,这样在启动的时候可以节省编译时间,减少CPU使用,加速启动。
QuickStart框架
QuickStart集成了AppCDS、EagerAppCDS、AOT等多种特性,旨在提升应用启动性能。
VectorAPI
Vector API是OpenJDK project Panama的一个重要组成部分,它的目标是让Java开发者更加自由的调用CPU强大的SIMD指令,让一条指令处理多条数据,从而获得成倍的性能提升。Vector API在大数据,AI计算和多媒体处理等。
目前大多数应用用的还是JDK 8,不知道高版本的JDK能带来什么收益,所以没有动力去升级,我理解升级JDK版本带来的收益核心有三点:
业界主流趋势 springboot 、netty、Kafka这些常用的框架在高版本里已不再支持低版本JDK(JDK8及以下)
首选 LTS版本, JDK 8以后LTS版本目前就两个,JDK 11和 JDK17,对应集团内的版本就是AJDK 11和 AJDK 17,直接从JDK 8 - JDK 17, 风险较高,由于没有经过JDK 11过渡,可能会出现测试未覆盖代码在线上运行时直接异常退出情况。
总的来看,目前选择JDK11是一个不错的选择,建议大家可以先升级JDK11, 如果有需求再升级JDK17, 如果有的同学对应用的代码和依赖完全可控, 可以直接升AJDK 17。
另外附上New Relic 2022年3月发布的一份Java 生态系统状况报告[1]供参考,该报告基于从数百万个提供性能数据的匿名应用程序中收集的数据。报告显示,JDK 11 采用率已经超过 JDK 8,已经成为生产环境的最新标准。
SPECjbb2015JDK8/11性能分析
SPECjbb2015是SPEC组织的一个用于评估服务器端Java应用性能的基准测试程序。
TPP升级后JDK版本后主要降低了P99指标。
店铺投放场景在应对突发流量的情况,升级JDK 11后超时Y率从6.58%降低至1.65%。
手猜工程场景,超时率从1.3%左右下降到了1.3‰左右,SLA从2个9变成了3个9,gc的次数跟gc耗时都有下降。
MTOP 升级 JDK 11 + G1 GC 后,单机QPS提升 11%,CPU降低 2 pt,RT降低 5%,YGC 平均次数 和 平均暂停时长均降低 40-50%,落到成本上可以缩减 MTOP 机器 10% 即 100 台左右 。
一些常用软件或框架的老版本不支持JDK11,需要进行升级。
常用的开发软件和插件的支持JDK11的最低版本:
# 构建打包使用jdk版本, aone编译机器上未安装最新版本的ajdk,
# 可以用已安装的ajdk版本进行编译,实际运行用最新版本的ajdk,最新版本的ajdk有较多新特性
baseline.jdk=ajdk11_11.0.14.13_fp2
# 升级maven版本,建议用amaven, amaven有代码编译加速的功能
build.tools.maven=amaven3.5.0
# 安装ajdk11 最新版本的jdk可以在这里查看 http://yum.tbsite.net/taobao/7/x86_64/current/ajdk11/
rpm -ivh --nodeps "http://yum.tbsite.net/taobao/7/x86_64/current/ajdk11/ajdk11-11.0.16.15_fp1-20220929100209.alios7.x86_64.rpm" \
# 把java目录软链到 /opt/taobao/java 目录,ajdk8自动连接,ajdk11 需要手动软链
rm -rf /opt/taobao/java ln -s /opt/taobao/install/ajdk11-11.0.16.15_fp1 opt/taobao/java \
# 去掉cms相关参数,删除下面两行
SERVICE_OPTS="${SERVICE_OPTS} -XX:+UseConcMarkSweepGC -XX:CMSMaxAbortablePrecleanTime=5000"
SERVICE_OPTS="${SERVICE_OPTS} -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly"
应用启动报错 io.netty.util.internal.PlatformDependent0 - direct buffer constructor: unavailable
SERVICE_OPTS="${SERVICE_OPTS} -Dio.netty.tryReflectionSetAccessible=true --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED --add-opens=java.base/java.nio=ALL-UNNAMED"
本文主要讲了JDK高版本的一些新特性、升级JDK 11带来的收益以及升级步骤和升级常见问题。总体来说, JDK 11 升级带来的收益是大于升级成本的(特别老的应用另说),希望本文能够帮助大家对高版本的JDK有一个全面的了解,对于有升级需要的同学也能有所帮助。
参考链接:
[1]https://newrelic.com/resources/report/2022-state-of-java-ecosystem
[2]https://blog.jetbrains.com/idea/2018/06/java-11-in-intellij-idea-2018-2/
[3]https://blog.codefx.org/https://marketplace.eclipse.org/content/java-11-support-eclipse-photon-49
[4]https://docs.gradle.org/5.0/release-notes.html#java-11-runtime-support
[5]https://adoptium.net/zh-CN/marketplace/?version=11
作者刘兵(多叶)
以上就是升级指南之JDK 11+ 新特性和AJDK(jdk11的新特性有哪些)的详细内容,想要了解更多 升级指南之JDK 11+ 新特性和AJDK的内容,请持续关注盛行IT软件开发工作室。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。