Java21上手体验-分代ZGC和虚拟线程

java21,上手,体验,zgc,虚拟,线程 · 浏览次数 : 19

小编点评

**一、介绍** 由于 Oracle 发布了 Java21 LTS 版本,引起了大家的关注。本文就分享我对 Java21 的升级体验,以及分代 ZGC 和虚拟线程的具体细节。 **二、更新内容介绍** * 新版本发布了 Java17 的更新版本,称为 Java21。 * Java21 引入了一些新特性,包括: * Record Patterns:一个新的编程模式,可以用来定义和访问对象的属性和方法。 * Vector API:一个用于存储和操作 Vector 的新 API。 **三、分代 ZGC 和虚拟线程** **3.1 分代 ZGC** * Java21 中引入了新的垃圾回收器,称为 分代 ZGC。 * 分代 ZGC 使用了标记和整理的技术来优化垃圾回收效率。 * 它可以将垃圾回收延迟到应用程序的内存紧张时。 **3.2 虚拟线程** * Java21 支持虚拟线程。 * 虚拟线程和平台线程相比,具有更低的创建和执行成本。 * 虚拟线程可以并发执行,但应注意它们的资源限制。 **四、新特性记录模式** * Record Patterns 是一个新的编程模式,可以用来定义和访问对象的属性和方法。 * 它可以帮助程序员编写更简洁和易读的代码。 * Record Patterns 可以用于创建嵌套的记录,从而模拟复杂的数据结构。 **五、结论** Java21 是一个强大的版本,它引入了许多新特性,可以帮助程序员编写更高效和可读的代码。分代 ZGC 和虚拟线程是 Java21 中非常重要的新特性,它们可以极大地提高应用程序的性能。

正文

一、导语

几天前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

模块数量比17少一个:
image.png

整体大小从289MB增加到了320MB

四、升级体验

下载

更新pom

image.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

五、分代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
image.png

使用Java21,使用分代ZGC

MooInfo内存占用查看
image.png
image.png
以上只是初步体验,关于ZGC的更多内容,如详细的分代回收情况后续进一步探索。

以上内存占用查看使用我之前做的一个工具,MooInfo:
https://github.com/rememberber/MooInfo

六、虚拟线程探索

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 密集型操作。

虚拟线程用法

Thread thread = Thread.ofVirtual().start(() -> System.out.println("Hello"));
thread.join();


或者

        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();
        }


或者

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();
        }
    }
}


或者

        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文档的用法,实际使用时我发现还可以这样:

 Thread.startVirtualThread(() -> {
                // do something
               
            });


平台线程和虚拟线程对比测试

为了测试对比,我建了一个项目

image.png

初步对比,和官网描述一致,计算密集型场景差别不大,IO密集型场景有明显改善
虚拟线程100个,IO读文件

平台线程100个,IO读文件

虚拟线程100个,Get请求百度首页

平台线程100个,Get请求百度首页

但是由于是本地测试,且用例比较简陋,无法完全得出准确结论。
日后大家有实际IO密集性多线程场景可以实际感受下。

线程池?忘了它吧

开发人员通常会将应用程序代码从基于线程池的传统 ExecutorService 迁移到虚拟线程每任务 ExecutorService。
线程池和所有资源池一样,旨在共享昂贵的资源,
但虚拟线程并不昂贵,而且永远不需要将它们池化。

七、一颗语法糖?Java21 新特性:Record Patterns

一个例子感受一下新特性:Record Patterns
before:

static void printSum(Object obj) {
    if (obj instanceof Point p) {
        int x = p.x();
        int y = p.y();
        System.out.println(x+y);
    }
}


after:

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

作者:京东科技 周波

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

与Java21上手体验-分代ZGC和虚拟线程相似的内容:

Java21上手体验-分代ZGC和虚拟线程

一、导语 几天前Oracle刚刚发布了Java21, 由于这是最新的LTS版本,引起了大家的关注。 我也第一时间在个人项目中进行了升级体验。 一探究竟,和大家分享。 二、Java21更新内容介绍 官方release公告: https://jdk.java.net/21/release-notes 开

Stream流处理快速上手最佳实践

一 引言 JAVA1.8得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成

Java21的虚拟线程Virtual Thread初体验

我们之前使用的是操作系统平台的线程,就称之为“系统线程”吧。虚拟线程是JDK维护的,原理跟WebFlux的底层实现差不多,都是工作线程分离。 要使用虚拟线程,需要使用JDK21以上,包括21。 虚拟线程可以创建很多很多 系统线程不能轻易创建太多,我们一直被教导创建线程是很重的活动。 for (int

一次惨痛的面试:“网易提前批,我被虚拟线程问倒了”

一、写在开头 昨晚收到一个粉丝在私信的留言如下: build哥,今天参加了网易的提前批,可以说是一次惨痛的面试体验,直接被虚拟线程问倒了,无论是在校学习的时候还是在公司实习的时候,都使用的是Java8更多,或者Java11,比较点子背的是面试我的这一个面试官,他们团队刚好在做Java21的切换,

Java 21新特性-虚拟线程 审核中

Java 21 版本更新中最重要的功能之一就是虚拟线程 (JEP 444)。这些轻量级线程减少了编写、维护和观察高吞吐量并发应用程序所需的工作量。

Java 21的StringBuilder和StringBuffer新增了一个repeat方法

发现Java 21的StringBuilder和StringBuffer中多了repeat方法: /** * @throws IllegalArgumentException {@inheritDoc} * * @since 21 */ @Override public StringBuilder

Java 21 新特性:Unnamed Classes and Instance Main Methods

Java 21引入了两个语言核心功能: 未命名的Java类你说 新的启动协议:该协议允许更简单地运行Java类,并且无需太多样板 下面一起来看个例子。通常,我们初学Java的时候,都会写类似下面这样的 Hello World 程序: public class HelloWorld { public

Java 21 新特性:Unnamed Patterns and Variables

Java 21中除了推出JEP 445:Unnamed Classes and Instance Main Methods之外,还有另外一个预览功能:未命名模式和变量(Unnamed Patterns and Variables)。该新特性的目的是提高代码的可读性和可维护性。 下面通过一个例子来理解

Java 21 新特性:虚拟线程(Virtual Threads)

在Java 21中,引入了虚拟线程(Virtual Threads)来简化和增强并发性,这使得在Java中编程并发程序更容易、更高效。 虚拟线程,也称为“用户模式线程(user-mode threads)”或“纤程(fibers)”。该功能旨在简化并发编程并提供更好的可扩展性。虚拟线程是轻量级的,这

Java 21 正式 GA,虚拟线程真的来了

UTC 时间 2023 年 9 月 19 日,期盼已久的 Java 21 终于发布正式版! 本文一起来看看其中最受 Java 开发者关注的一项新特性:Loom 项目的两个新特性之一的 ”虚拟线程(Virtual Thread)“(另外一个新特性是 ”结构化并发(Structured Concurre