您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
Java21上手体验-分代ZGC和虚拟线程
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
Java21上手体验-分代ZGC和虚拟线程
yu****
2023-10-06
IP归属:北京
10160浏览
## 一、导语 几天前Oracle刚刚发布了Java21, 由于这是最新的LTS版本,引起了大家的关注。 我也第一时间在个人项目中进行了升级体验。 一探究竟,和大家分享。 ## 二、Java21更新内容介绍 ### 官方release公告: https://jdk.java.net/21/release-notes ### 开源中国介绍: https://my.oschina.net/waylau/blog/10112170 ### 新特性一览: * JEP 431:序列集合 * JEP 439:分代 ZGC * JEP 440:记录模式 * JEP 441:switch 模式匹配 * JEP 444:虚拟线程 * JEP 449:弃用 Windows 32 位 x86 移植 * JEP 451:准备禁止动态加载代理 * JEP 452:密钥封装机制 API * JEP 430:字符串模板(预览) * JEP 442:外部函数和内存 API(第三次预览) * JEP 443:未命名模式和变量(预览) * JEP 445:未命名类和实例主方法(预览) * JEP 446:作用域值(预览) * JEP 453:结构化并发(预览) * JEP 448:Vector API(孵化器第六阶段) 其中大家比较关注的是分代 ZGC和虚拟线程。 ## 三、开箱 ### 下载地址: > OpenJDK 版本:https://jdk.java.net/21/ > Oracle 版本:https://www.oracle.com/java/technologies/downloads/ ### 对比17 ~~边框由不锈钢升级为钛金属~~ 目录结构一致: ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-22-16-57uWUxzHdR4IiGA16.png) 模块数量比17少一个: ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-22-16-59NmOtraG30TLb7aOY.png) 整体大小从289MB增加到了320MB ## 四、升级体验 ### 下载 ![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-27-20-20KPkiWh20ANpwDaA6.jpg) ### 更新pom ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-22-17-02RcxH6JLt226patbA.png) ### 尝试运行 运行报错: `java.lang.NoSuchFieldError: Class com.sun.tools.javac.tree.JCTree$JCImport does not have member field 'com.sun.tools.javac.tree.JCTree qualid' ` 解决办法: 升级lombok至1.18.30 > 原因:https://github.com/projectlombok/lombok/issues/3393 ### 兼容性检查: 由于我的项目以前用的JDK17,本次升级兼容性良好,只发现了一处: 系统托盘中 使用了PopupMenu,出现了字符集问题: ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-22-17-06rHX0SMC22KwSPUtW.png) ## 五、分代ZGC体验 ZGC在之前的JDK版本中也有,这次的分代ZGC更是被大家看好,官方的介绍如下: > Applications running with Generational ZGC should enjoy: > > Lower risks of allocations stalls, > Lower required heap memory overhead, and > Lower garbage collection CPU overhead. > Enable Generational ZGC with command line options -XX:+UseZGC -XX:+ZGenerational 性能测试参考: > https://inside.java/2023/09/03/roadto21-performance/ ### JVM参数:-XX:+UseZGC -XX:+ZGenerational ### 使用Java21,未使用ZGC MooInfo内存占用查看 ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-22-17-45N25MWZpD45tqShhci.png) ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-22-17-45khK8C45WuuJ45JjQJ.png) ### 使用Java21,使用分代ZGC MooInfo内存占用查看 ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-22-17-42ffee940YYLl5lMh22.png) ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-22-17-43Bhc0rCPJeIcKAzy.png) 以上只是初步体验,关于ZGC的更多内容,如详细的分代回收情况后续进一步探索。 以上内存占用查看使用我之前做的一个工具,MooInfo: [https://github.com/rememberber/MooInfo](https://github.com/rememberber/MooInfo) ![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-22-20-42hX9BCDG52V9Xx52LZ.png) ## 六、虚拟线程探索 Virtual threads are lightweight threads that reduce the effort of writing, maintaining, and debugging high-throughput concurrent applications. 虚拟线程是轻量级线程,可以减少编写、维护和调试高吞吐量并发应用程序的工作量。 Oracle介绍原文: > https://docs.oracle.com/en/java/javase/20/core/virtual-threads.html#GUID-DC4306FC-D6C1-4BCC-AECE-48C32C1A8DAA ### 平台线程 Oracle官方文档的机器翻译: > 平台线程是作为操作系统(OS)线程的瘦包装器实现的。 > 平台线程在其底层操作系统线程上运行Java代码,平台线程在平台线程的整个生命周期内捕获其操作系统线程。 > 因此,可用平台线程的数量受限于操作系统线程的数量。 > 平台线程通常有一个大的线程堆栈和其他由操作系统维护的资源。 > 平台线程支持线程局部变量。 > 平台线程适合运行所有类型的任务,但可能是有限的资源。 ### 虚拟线程 Oracle官方文档的机器翻译: > 与平台线程一样,虚拟线程也是 java.lang.Thread 的一个实例。 > 但是,虚拟线程并不依赖于特定的操作系统线程。 > 虚拟线程仍然在操作系统线程上运行代码。 > 但是,当虚拟线程中运行的代码调用阻塞 I/O 操作时,Java 运行时会挂起虚拟线程,直到可以恢复为止。 > 与挂起的虚拟线程关联的操作系统线程现在可以自由地为其他虚拟线程执行操作。 实现原理 > 虚拟线程的实现方式与虚拟内存类似。 > 为了模拟大量内存,操作系统将较大的虚拟地址空间映射到有限的 RAM。 > 同样,为了模拟大量线程,Java运行时将大量虚拟线程映射到少量操作系统线程。 > 与平台线程不同,虚拟线程通常具有浅调用堆栈,只执行单个 HTTP 客户端调用或单个 JDBC 查询。 > 尽管虚拟线程支持线程局部变量,但您应该仔细考虑使用它们,因为单个 JVM 可能支持数百万个虚拟线程。 **虚拟线程适合运行大部分时间处于阻塞状态、通常等待 I/O 操作完成的任务。 但是,它们不适用于长时间运行的 CPU 密集型操作。** ### 虚拟线程用法 ```java Thread thread = Thread.ofVirtual().start(() -> System.out.println("Hello")); thread.join(); ``` 或者 ```java try { Thread.Builder builder = Thread.ofVirtual().name("MyThread"); Runnable task = () -> { System.out.println("Running thread"); }; Thread t = builder.start(task); System.out.println("Thread t name: " + t.getName()); t.join(); } catch (InterruptedException e) { e.printStackTrace(); } ``` 或者 ```java public class CreateNamedThreadsWithBuilders { public static void main(String[] args) { try { Thread.Builder builder = Thread.ofVirtual().name("worker-", 0); Runnable task = () -> { System.out.println("Thread ID: " + Thread.currentThread().threadId()); }; // name "worker-0" Thread t1 = builder.start(task); t1.join(); System.out.println(t1.getName() + " terminated"); // name "worker-1" Thread t2 = builder.start(task); t2.join(); System.out.println(t2.getName() + " terminated"); } catch (InterruptedException e) { e.printStackTrace(); } } } ``` 或者 ```java try (ExecutorService myExecutor = Executors.newVirtualThreadPerTaskExecutor()) { Future<?> future = myExecutor.submit(() -> System.out.println("Running thread")); future.get(); System.out.println("Task completed"); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } ``` **以上是Java20文档的用法,实际使用时我发现还可以这样:** ```java Thread.startVirtualThread(() -> { // do something }); ``` ### 平台线程和虚拟线程对比测试 **为了测试对比,我建了一个项目 ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-22-20-06bLo9hZRaEcFkonp.png) **初步对比,和官网描述一致,计算密集型场景差别不大,IO密集型场景有明显改善**: 虚拟线程100个,IO读文件 ![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-27-20-218AWBVO978c8bShr.jpg) 平台线程100个,IO读文件 ![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-27-20-22A8jlSCSj27sEayCG.jpg) 虚拟线程100个,Get请求百度首页 ![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-27-20-22TaZuSkUcAvX7se9.jpg) 平台线程100个,Get请求百度首页 ![](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2023-09-27-20-22cjFuetKsygTmm6P.jpg) 但是由于是本地测试,且用例比较简陋,无法完全得出准确结论。 日后大家有实际IO密集性多线程场景可以实际感受下。 ### 线程池?忘了它吧 开发人员通常会将应用程序代码从基于线程池的传统 ExecutorService 迁移到虚拟线程每任务 ExecutorService。 线程池和所有资源池一样,旨在共享昂贵的资源, 但虚拟线程并不昂贵,而且永远不需要将它们池化。 ## 七、一颗语法糖?Java21 新特性:Record Patterns 一个例子感受一下新特性:Record Patterns before: ```java static void printSum(Object obj) { if (obj instanceof Point p) { int x = p.x(); int y = p.y(); System.out.println(x+y); } } ``` after: ```java static void printSum(Object obj) { if (obj instanceof Point(int x, int y)) { System.out.println(x+y); } } ``` 参考:https://my.oschina.net/didispace/blog/10112428
上一篇:【后台体验】运营后台订单详情设计分享
下一篇:浅入深出的微前端MicroApp
yu****
文章数
5
阅读量
674
作者其他文章
01
Java21上手体验-分代ZGC和虚拟线程
一、导语几天前Oracle刚刚发布了Java21,由于这是最新的LTS版本,引起了大家的关注。我也第一时间在个人项目中进行了升级体验。一探究竟,和大家分享。二、Java21更新内容介绍官方release公告:https://jdk.java.net/21/release-notes开源中国介绍:https://my.oschina.net/waylau/blog/10112170新特性一览:JEP
01
【后台体验】运营后台订单详情设计分享
目前大部分运营后台的设计和开发都是由后端同学来做,产品经理对界面标准要求并不高,大多数都是能用就行。其实,只要花些心思,运营后台也可以做的很美,提升运营同学的日常使用体验。下面跟大家分享两个我做的运营后台中的订单详情设计1.共享图书平台运营后台订单详情设计心路历程:产品经理并没有要求如何展示,仅提供想要看的内容,所以自由发挥如图该后台面向对象主要是仓库运营和图书运营人员,核心关注改订单包含哪些书
01
jar包的精细化运营,Java模块化简介
图:模块化手机概念一、什么是Java模块化Java模块化(module)是Java9及以后版本引入的新特性。官方对模块的定义为:一个被命名的,代码和数据的自描述集合。( the module, which is a named, self-describing collection of code and data)。早在Java7的时候就被提出,但由于其复杂性,不断跳票,直到Java9才有,那么
01
Java模块化应用实践之精简JRE
导语Java9及以后的版本引入了模块化特性,但是直到今天JDK21都发布了,依然没有被大量使用起来,那么这个特性就真的没啥意义了吗?别忘了,Java本身可是把模块化做到了极致的,所以可以利用这个特性对JRE本身进行定制化或者精简化。由于平时偶尔会开发一些Java的客户端应用,这时精简JRE的需求就凸显出来,让自己的程序带着最精简的JRE到处运行。实际实践了一段时间之后发现“真香!”现在把“利用Ja
yu****
文章数
5
阅读量
674
作者其他文章
01
【后台体验】运营后台订单详情设计分享
01
jar包的精细化运营,Java模块化简介
01
Java模块化应用实践之精简JRE
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号