JDK8升级JDK11最全实践干货来了 | 京东云技术团队

news2024/11/22 17:42:50

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效果

先给出结论:

  1. JDK11相对于JDK8,所有垃圾回收器的性能都有提升,特别是大内存机器下G1的提升最明显
  2. 8G内存以下的机器,推荐使用Parallel GC,如果特别追求低延迟,选择牺牲吞吐量,可以使用G1,并设置期望的最大垃圾回收停顿时间来控制
  3. 8G及以上的大内存机器,推荐使用G1 4、不推荐使用CMS,升级后从各项数据来看,CMS收集器都不如G1

我在JDOS平台上选择了不同配置的机器(2C4G、4C8G、8C16G),并分别使用JDK8和JDK11进行部署和压测。

整个压测过程限时60分钟,用180个虚拟用户并发请求一个接口,每次接口请求都创建512Kb的数据。最终产出不同GC回收器的各项指标数据,来分析GC的性能提升效果。

以下是压测的性能情况:

* 上面给出的GC升级效果,采用的是默认的配置,没有做任何优化,只提供参考。真正的GC调优是个技术活,需要根据业务需求、机器配置和实际压测效果等综合评估来选出最合适的GC垃圾回收器。

* 不同垃圾回收器的特点:

  1. Parallel GC - JDK 8及以下版本的默认收集器,关注吞吐量,尝试在最小延迟的情况下尽快完成工作并提高吞吐量。

  2. CMS - 一个老年代收集器,基于标记-清除算法实现,关注延迟,以最短回收停顿时间为目标

  3. 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 工具包

字符串方法增强isBlanklinesstripstripLeadingstripTrailingrepeat

Files增强:readString、WriteString

InputStream增强:transferTo(流快速拷贝)

stream增强,dropWhile(从集合中删除满足的)、takeWhile(从集合中获取满足的)、ofNullable

集合工厂方法:Sets.of()、List.of()、Map.of()、Map.ofEntries(),举例:List list = List.of(“Java”, “Python”, “C++”);

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应用程序,它将代码分为相互独立、可复用的模块。每个块都有自己的命名空间,明确声明并控制其他模块的访问权限。这种模块化设计使得开发人员能够更好地维护复杂的应用程序,提高代码的复用性、可维护性和安全性,同时提升应用的加载速度和性能**。**最大的特点是可以定义模块描述符来隔离module(Jar包)内部类的访问权限。

模块化的几点关键说明:

1)相对于JDK8的变动

  • JDK9以后引入了一个新组件module:模块描述符module-info.java,用于将一组相关的包放入一个组中。
  • 在Java8和更早的应用程序中,应用程序将包作为顶级组件,Java9以后应用程序将模块作为顶级组件
  • 一个模块(Jar包)只能有一个module-info.java。

2)和maven的关系

模块化并不是要替代maven,和maven本身并不冲突,maven定义jar之间的依赖关系,模块化是对已经依赖的jar下的包进行更细粒度依赖控制

3)如何兼容旧应用

天然兼容旧应用。为了向后兼容旧项目,一些库本身并未模块化,其仍然可以作为模块在模块路径中使用,而这些库在模块路径上时会被转化为自动模块,例如:jackson-databind-1.0.0.jar将成为自动模块jackson.databind

6.2、带来了哪些好处?

1)封装和隔离,更好的访问控制

模块化允许开发者将代码和资源封装在独立的模块中。模块之间可以明确地定义公开和私有的API,提供了更好的代码隔离性和可维护性。

ps:新业务单应用可以按照领域模型来进行多模块的划分,以避免代码腐化。简单举例单应用下存在产品.jar、订单.jar。订单依赖产品,通过模块化的限制,订单只能使用产品中明确对外暴露的类,这样就避免传统模式订单.jar可能依赖了产品.jar中普通的类导致代码腐化的问题,也降低后续领域服务拆分的复杂度

2)更好的可伸缩性,加载速度的提升

模块化系统使得Java平台更加可伸缩,通过模块化定义,可以仅加载需要的模块,从而提升加载类的效率,最终减少了应用程序的内存占用和启动时间,同时打包后的程序也更小。

3)明确的依赖关系

模块化系统要求在模块之间明确定义依赖关系。在编译或运行代码之前,模块系统会检查模块是否满足所有依赖关系,从而导致更少的运行时错误。

4)安全

在JVM的最深层次上执行强封装,减少Java运行时的攻击面,同时无法获得对敏感内部类的反射访问。

6.3、如何使用

1)定义module-a.jar

包结构如下:

com.jdt.a
        person
            Men.java
        reflect
            ReflectModel.java
        module-info.java    




module-info文件内容如下:

module module.a { 
    //指令用于指定一个模块中哪些包下的public对外是可访问的,包括直接引入和反射使用 
    exports com.jdt.a.person; 
    // 只能被反射调用,用于指定某个包下所有的 public 类都只能在运行时可被别的模块进行反射,并且该包下的所有的类及其乘员都可以通过反射进行访问。 
    opens com.jdt.a.refect; 
}




2)定义module-b.jar,包的pom中指定依赖了module-a

包结构如下:

com.jdt.b
        test
            Test.java
        module-info.java    




module-info文件内容如下:

module module.b {
     //依赖a下的包
     requires module.a;
}




3)此时module-b.jar,在编写编码时,会遇到如下问题

6.4、实践过程的坑

上面简单介绍了模块化的知识,具体在落地过程中,我们主要踩了以下的坑,供大家参考

1)依赖JSF包时无法模块化

* JSF是京东内部使用的高性能RPC框架

进行模块化时,pom中依赖了jsf包,模块定义如下:

module module.a {
    requires  fastjson;
    //依赖jsf包名
    requires  jsf.lite;

    exports com.jd.jdk.test.module;
}




此时编译报错如下:提示找不到模块:jsf.lite,但是pom中明明指定依赖了jsf.lite

问题原因:

经过一系列定位研究,发现jsf-lite包中,/META-INF/services下的文件org.glassfish.jersey.internal.spi.AutoDiscoverable里面写的类是com.alibaba.fastjson.support.jaxrs.FastJsonAutoDiscoverable,此类并未在当前jsf.lite包中定义,属于com.alibaba.fastjson包的。

但是我们的pom中明明也依赖了com.alibaba.fastjson包,为什么模块化后,就找不到了呢?

主要原因在于模块化遇到SPI(Service Provider Interface)时的约束:模块化时,SPI机制要求配置中定义依赖的类必须本模块定义的,不能是其他模块的包(来自它不拥有的包),否则,此包将无法被模块化

这样也就解释了,为什么上面jsf无法找到module的问题,jsf-lite里面设置了它不拥有的包:com.alibaba.fastjson.support.jaxrs.FastJsonAutoDiscoverable,导致jsf-lite包无法被自动模块化

解决方案:

1、联系JSF团队,升级JSF包,修复上面说的FastJsonAutoDiscoverable配置错误的问题。

2)拆包问题(模块隔离)

模块化约束:jdk9以上,使用模块化时不支持拆分包的形式依赖

拆分包意味着两个模块包含相同的包,Java模块系统不允许拆分包。拆分包始终是不正常的,而当使用解析可传递依赖项的构建工具(如Maven等)时,很容易出现同一个库的多个版本,当Java模块系统检测到一个包存在于模块路径上的多个模块中时,就会拒绝启动。

例如:

module-a.jar包结构定义:
com.foo.package
    A.java
    
module-b.jar包结构定义:
com.foo.package
    B.java   




当module-c同时依赖module-a和module-b时,如上编译时会报一个错,Package com.foo.package in both module module.b and module module.a,这就是JAVA9的模块隔离,要求只能从一个模块(module)中读取同一个包(package),不能跨模块读取。

解决方案:

如果在使用模块化时,遇到了拆分包问题,无论如何都是无法绕过的。即使从用户角度来看基于类路径的应用程序可以正确工作,你也最终需要处理这些问题。此时只能停用模块化或升级jar包,避免拆分包问题

6.5、模块化落地总结

目前不推荐使用模块化,因为相关组件生态还不完善,并且模块化带来的价值不够突出:

  1. 很多中间件都是基于jdk8构建的,都有可能遇到模块化兼容的问题,比如:jsf,需要jsf强制升级才可以使用模块化

  2. 拆包问题无法解决,比如:aws-java-sdk-s3、fluent等。

7、总结

  1. 升级过程简单,升级后可以使用更多新特性和更好的GC性能,所以 建议升级到JDK11
  2. 现阶段 不推荐使用模块化,但是不用担心会影响JDK11的升级。

另外听说JDK17的 ZGC可以达到亚秒级停顿,但考虑到JDK11的ZGC还不是很稳定,所以本次不做测试,后面升级到JDK17后再给大家分享ZGC压测效果。

希望以上分享可以给大家带来实际的帮助。

作者:京东科技 曲振富

来源:京东云开发者社区 转载请注明来源

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1022133.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

js中哪些地方会用到window?

前言 Window 对象是JavaScript中的顶层对象,它代表了浏览器中打开的窗口或者标签页。浏览器中打开的每一个窗口/标签页都会有一个对应的 Window 对象。在浏览器中,全局作用域的 this 就是指向 Window 对象。 正文 在 JavaScript 中,window 对…

《Python趣味工具》——自制emoji3

今日目标 在上次,我们绘制了静态的emoji图。并且总结了turtle中的常用函数。 本次我们将尝试制作一个动态的emoji,让你的表情包动起来! 文章目录 一、动画原理:二、制作动画:1. 修改eyes_black()函数:2. 绘…

构建可维护的大规模应用:框架架构的最佳实践

文章目录 框架架构的重要性最佳实践1. 模块化设计2. 遵循SOLID原则3. 使用设计模式4. 异常处理5. 代码注释和文档6. 测试 Spring Boot 和 Django:关键框架示例Spring Boot(Java)模块化设计:SOLID原则:设计模式&#xf…

分类散点图 stripplot() 加辅助线axhline() 多图合一

分类散点图 stripplot 加辅助线axhline 多图合一 效果图代码 画图没有什么可说的,直接上图 效果图 代码 # 绘制图, 查看是否数值在阈值上 plt.figure(figsize(30, 18)) n 0 for header, value_list in info_dict.items():ref_value_list ref_info_dic…

three.js——通过顶点和顶点索引创建集合体

通过顶点和顶点索引创建集合体 效果图1、创建顶点数据2、创建顶点属性3、创建材质4、创建网格5、改变网格的位置并添加到场景中6、通过顶点索引创建几何图形 效果图 1、创建顶点数据 // 创建顶点数据 每三个一个顶点 逆时针为正面 const vertices new Float32Array([ -1.0, -…

uTool快捷指令

send("************"); quickcommand.sleep(200); keyTap("enter");

关于微信小程序rich-text中图片宽度超出范围解决办法

问题描述:写一个富文本展示页面时发现一个问题,就是图片宽度超出范围,本能反应是给图片设置一个最大宽度,这里发现不可行。然后又使用正则追加样式还是不行。 // 使用正则提取html里面的图片设置图片最大宽度为100% res[1].data[0…

netty-HashedWheelTimer源码解析

一、案例分析 public void testExecutionOnTaskExecutor() throws InterruptedException {int timeout 10;final CountDownLatch latch new CountDownLatch(1);final CountDownLatch timeoutLatch new CountDownLatch(1);Executor executor new Executor() {Overridepublic…

用纯html写个个人简历!模版分享啦!!!

用纯html写个个人简历!首先得先找个模板! 一个优秀模板所应该具有的素质? 简单? 仅仅一个html页面,完全没有乱七八糟,保证学的明明白白。 漂亮? 该有的内容一个不少! 个人照片&a…

零基础Linux_6(开发工具_下)函数库链接+Makefile+实现进度条+Git

目录 1. 函数库(链接) 1.1 链接 1.2 动态库与静态库 2. makefile 2.1 项目构建 2.2 Makefile的概念 2.3 Makefile的编写 2.4 .PHONY定义伪目标 ACM 时间 3.实现进度条(缓冲区) 3.1 缓冲区的概念 3.2 实现一个简易 &q…

全网最详细的OSPF原理总结,看这篇就够了!

大家好,我的网工朋友。 OSPF是一种基于链路状态的路由协议,也是专为 IP 开发的路由协议,直接运行在 IP 层上面。它从设计上保证了无路由环路。除此之外,IS-IS也是很常见的链路状态协议。 为什么会出现OSPF? 作为目前…

欧拉操作系统在线安装mysql8数据库并用navicat premium远程连接

网上太多安装教程,但是没有一个教程能够一站式解决安装问题,而我不一样,我写的每一个博客,都是我自己试验过很多次,能够确保一站式解决,才会发上去,希望能够帮助到大家 第一步:升级…

Linux工具(一)

前言:Linux是一个开源的操作系统,它拥有庞大而活跃的开发社区,为用户提供了丰富多样的工具和应用程序。这些工具不仅适用于系统管理员和开发人员,也适用于普通用户,可以帮助他们完成各种任务,从简单的文件管…

爬虫 — Scrapy 框架安装问题

整理几个关于安装 Scrapy 框架时会遇到的问题及解决方法。 1、 pip install typing-extensions4.3.0 -i https://pypi.douban.com/simple 2、 pip install pyOpenSSL22.0 -i https://pypi.douban.com/simple 3、 pip install cryptography36.0.2 -i https://pypi.douban.com/s…

基于GBDT+Tkinter+穷举法按排队时间预测最优路径的智能导航推荐系统——机器学习算法应用(含Python工程源码)+数据集(四)

目录 前言总体设计系统整体结构图系统流程图 运行环境Python环境Pycharm 环境Scikit-learnt 模块实现1. 数据预处理2. 客流预测3. 百度地图API调用4. GUI界面设计5. 路径规划6. 智能推荐 系统测试1. 训练准确率2. 测试效果3. 程序应用 相关其它博客工程源代码下载其它资料下载 …

如何在云服务器上成功安装MongoDB数据库并用Python连接(问题及解决方法)

最近购买了1台腾讯云轻量服务器做测试,想在上面安装MongoDB数据库。但安装过程并不顺利,遇到了几个问题。本文记录一下安装过程及遇到的问题和解决方法。 一、软件下载地址: 1.直接打开MongoDB官网:https://www.mongodb.com/ …

2023 Google 开发者大会:助力传承和弘扬传统文化

文章目录 前言一、关于 Google 开发者大会1.1、什么是 Google 开发者大会?1.2、CSDN 上线 2023 Google 开发者大会专题页 二、敦煌深厚的艺术沉淀2.1、“云想衣裳花想容”?2.2、“大漠孤烟直,长河落日圆” 三、传统文化赋予现代艺术设计灵感四…

1.IAR-8051安装

新版安装教程:IAR EW for 8051 简介与安装 新版软件zhuce:IAR EW for 8051 软件注册 - 知乎 这个新版的我也放到网盘里面了,自己自行选择安装 一、下载IAR-8051 链接:https://pan.baidu.com/s/1mYwSQvSjAiSzltrEbK3yAw?pwd43cd …

IPV4和IPV6,公网IP和私有IP有什么区别?

文章目录 1、什么是IP地址?1.1、背景1.2、交换机1.3、局域网1.4、广域网1.5、ISP 互联网服务提供商 2、IPV42.1、什么是IPV4?2.2、IPV4的组成2.3、NAT 网络地址转换2.4、端口映射 3、公网IP和私有IP4、IPV6 1、什么是IP地址? 1.1、背景 一台…

接口调用三种方式

创建服务端 一个controller,一个启动类,配置端口 controller import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RestController public class ServerController {Req…