1、前言
截至目前(2023年),Java8发布至今已有9年,2018年9月25日,Oracle发布了Java11,这是Java8之后的首个LTS版本。那么从JDK8到JDK11,到底带来了哪些特性呢?值得我们升级吗?而且升级过程会遇到哪些问题呢?带着这些问题,本篇文章将带来完整的JDK8升级JDK11最全实践。
2、为什么升级JDK11
1)性能提升
更好的垃圾收机制、更快的类加载器, 加快应用程序的运行速度。综合评估,从Java 8 升级到 Java 11,G1GC平均速度提升16.1%,ParallelGC为4.5%(基于OptaPlanner的用例基准测试表明)
2)特性和改进
局部变类型推断、新的 API、HTTP/2客户端、Lambda表达式的新特性等,这些新特性可以提高开发效率。
3)支持最新的技术和框架
许多新的技术和框架已经或即将开始依赖于JDK11或以上版本,升级后可以保证应用程序能够分利用这些新的技术和框架。
4)长期支持版本
JDK11是Oracle官方发布的一个长期支持(LTS),意味着它将获得长期的更新和支持,有助于保持用程序的稳定性和可靠性。
5)行业趋势
数据来自 New Relic 在2023年1月发布的Java生态报告,从下图可以看出:
- 目前市面上有 超过 56%的应用程序使用了JDK 11,Java 8 的使用从2020年的84%降低到了现在的32%左右。大部分公司在这三年之间都升级到了JDK 11 或者 JDK 17这两个LTS版本上面。
- 垃圾收集器使用情况来看,JDK11版本及以上 G1使用率最高,占比高达65%
3、升级后GC效果
先给出结论:
- JDK11相对于JDK8,所有垃圾回收器的性能都有提升,特别是大内存机器下G1的提升最明显
- 8G内存以下的机器,推荐使用Parallel GC,如果特别追求低延迟,选择牺牲吞吐量,可以使用G1,并设置期望的最大垃圾回收停顿时间来控制
- 8G及以上的大内存机器,推荐使用G1 4、不推荐使用CMS,升级后从各项数据来看,CMS收集器都不如G1
我在JDOS平台上选择了不同配置的机器(2C4G、4C8G、8C16G),并分别使用JDK8和JDK11进行部署和压测。
整个压测过程限时60分钟,用180个虚拟用户并发请求一个接口,每次接口请求都创建512Kb的数据。最终产出不同GC回收器的各项指标数据,来分析GC的性能提升效果。
以下是压测的性能情况:
* 上面给出的GC升级效果,采用的是默认的配置,没有做任何优化,只提供参考。真正的GC调优是个技术活,需要根据业务需求、机器配置和实际压测效果等综合评估来选出最合适的GC垃圾回收器。
* 不同垃圾回收器的特点:
-
Parallel GC - JDK 8及以下版本的默认收集器,关注吞吐量,尝试在最小延迟的情况下尽快完成工作并提高吞吐量。
-
CMS - 一个老年代收集器,基于标记-清除算法实现,关注延迟,以最短回收停顿时间为目标
-
Garbage First(G1)- JDK 9以后的默认收集器,G1 关注总体的性能,会尝试在吞吐量和延迟之间做平衡。
4、JDK11带来了哪些新特性
4.1、GC改进
默认垃圾回收器改为G1,废弃CMS垃圾回收器
? G1特点:目标是降低应用程序的停顿时间并提高吞吐量。
引入ZGC垃圾回收器(可伸缩低延迟垃圾收集器) 但由于JDK11中ZGC还不够完善,推荐在JDK17中再使用稳定版ZGC
? Full GC的停顿不超过10毫秒
? 支持TB级堆内存回收
? 相对于G1吞吐量下降不超过15%
4.2、模块化
Java9引入了对于模块化软件支持,而Java11进一步扩展了这种特性。模块化让应用程序 更精简,减少对其他类库的依赖和冗余代码,提高运行效率和安全性 。
然而,目前不推荐使用模块化,因为相关组件生态还不完善,并且模块化带来的价值不够突出。具体原因请看后面章节的详细分析:新特性实践-模块化。
4.3、语法增强
? 局部变量推断,引入var局部变量类型,允许开发人员省略通常不必要的局部变量类型初始化声明
? Lambda表达式简化,内部可以使用var
? 接口中可以定义私有方法,可以实现接口方法的访问控制和代码复用
4.4、API增强
? HTTPClient标准化支持:强大而灵活的HTTP客户端API,支持多协议(HTTP/2、WebSocket)、异步非阻塞、流操作和连接池等特性。ps:再也不需要用第三包 HttpClient 工具包
? 字符串方法增强:isBlank
、lines
、strip
、stripLeading
、stripTrailing
和repeat
? Files增强:readString、WriteString
? InputStream增强:transferTo(流快速拷贝)
? stream增强,dropWhile(从集合中删除满足的)、takeWhile(从集合中获取满足的)、ofNullable
? 集合工厂方法:Sets.of()、List.of()、Map.of()、Map.ofEntries(),举例:List
5、如何升级
5.1、升级应用评估
- 为保证稳定性,我们优先在新业务新应用来落地实施JDK11的升级。
5.2、JDK选择
自从2019年1月起,Oracle JDK后续的版本开始商用收费,所以推荐大家选择OpenJDK11,OpenJDK和OracleJDK功能上没有差异,支持免费商用。
OpenJDK11下载地址:https://jdk.java.net/archive/
5.3、GC配置
根据自身需求和机器配置选择GC,不同GC的JVM启动参数配置:
- G1垃圾回收器(JDK11默认,不需要手动配置):-XX:+UseG1GC
- Parallel GC垃圾回收器:XX:+UseParallelGC
5.4、升级过程踩坑
整个升级过程还是比较简单的,除了升级JDK版本,实际遇到的问题如下:
5.5、升级后验证
升级后完成,做好单测和回归测试,推荐能做个压测验证,防止影响线上服务稳定性
6、新特性实践-模块化
Java一直是构建大型应用程序的主流语言之一。然而随着Java生态系统中存在着大量库和复杂的代码块之间关系难以理清的问题,构建系统变得困难且超出了我们的理解和有效开发的范围。特别是在使用繁多的Java存档文件(Java Archive, JAR)时,这一问题变得更加突出。为了应对这种复杂性,模块化能够很好地管理和减少代码的复杂性。因此自Java9开始,引入了模块化系统。通过模块化,Java本身也得以进行模块化改进。
6.1、模块化是什么?
模块化指的是JAVA平台的模块系统(Java Platform Module System),简称JPMS。JPMS引入一种新方式来组织和构建Java应用程序,它将代码分为相互独立、可复用的模块。每个块都有自己的命名空间,明确声明并控制其他模块的访问权限。这种模块化设计使得开发人员能够更好地维护复杂的应用程序,提高代码的复用性、可维护性和安全性,同时提升应用的加载速度和性能。****最大的特点