小工具知识网

当前位置: 首页 > 行业知识 > JDK21 新特性

行业知识

JDK21 新特性

2026-10-26 02:24:17 来源:互联网转载

目录

    • 1. 虚拟线程(Virtual Threads)
    • 2. 有序集合(Sequenced Collections)
    • 3. switch 的模式匹配(Pattern Matching for switch)
    • 4. 记录模式(Record Patterns)
    • 5. ZGC
    • 6. 准备禁用动态代理(Prepare to Disallow the Dynamic Loading of Agents)

      1. 虚拟线程(Virtual Threads)

      https://openjdk.org/jeps/444

      • 虚拟线程是工作在平台线程之上的,虚拟线程的数量可以远大于操作系统线程的数量,多个虚拟线程挂载在一个平台线程上,一个平台线程可以在不同的时间执行不同的虚拟线程,当虚拟线程被阻塞或等待时,平台线程可以切换到执行另一个虚拟线程。

        注意事项:

        1. 虚拟线程主要作用是提升服务器端的吞吐量,而不是提高线程的执行速度。
        2. 虚拟线程只适合IO密集型的任务,阻塞期间可以将CPU资源让渡给其他任务,不适合CPU密集型的任务或非阻塞任务。
        3. 虚拟线程是廉价且轻量级的,使用完后立即被销毁,因此不需要池化。
        • 创建虚拟线程的方法
          import lombok.extern.slf4j.Slf4j;import java.time.Duration;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ThreadFactory;import java.util.stream.IntStream;@Slf4jpublic class Demo {    public static void main(String[] args) throws Exception {        Runnable task = () -> {            log.info(Thread.currentThread().toString());        };        // 1. 通过 Thread.ofVirtual() 创建        Thread thread = Thread.ofVirtual().name(Thread.currentThread().toString()).start(task);        // 2. 通过 Thread.startVirtualThread() 创建        Thread.startVirtualThread(task);        // 3. 通过 ThreadFactory 创建        ThreadFactory factory = Thread.ofVirtual().factory();        Thread newThread = factory.newThread(task);        newThread.start();        // 4. 通过 Executors.newVirtualThreadPerTaskExecutor() 创建        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {            IntStream.range(0, 5).forEach(i -> {                executor.submit(() -> {                    log.info("{}, before", Thread.currentThread());                    try {                        Thread.sleep(Duration.ofSeconds(1));                    } catch (InterruptedException e) {                        throw new RuntimeException(e);                    }                    log.info("{}, after", Thread.currentThread());                });            });        }        System.in.read();    }}
          • 打印
            19:49:16.027 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#22]/runnable@ForkJoinPool-1-worker-219:49:16.027 [Thread[#1,main,5,main]] INFO org.example.virtual_thread.Demo -- VirtualThread[#20,Thread[#1,main,5,main]]/runnable@ForkJoinPool-1-worker-119:49:16.029 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#23]/runnable@ForkJoinPool-1-worker-219:49:16.029 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#25]/runnable@ForkJoinPool-1-worker-1, before19:49:16.030 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#27]/runnable@ForkJoinPool-1-worker-2, before19:49:16.029 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#26]/runnable@ForkJoinPool-1-worker-2, before19:49:16.031 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#28]/runnable@ForkJoinPool-1-worker-1, before19:49:16.031 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#29]/runnable@ForkJoinPool-1-worker-1, before19:49:17.033 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#27]/runnable@ForkJoinPool-1-worker-1, after19:49:17.033 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#25]/runnable@ForkJoinPool-1-worker-2, after19:49:17.033 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#28]/runnable@ForkJoinPool-1-worker-2, after19:49:17.033 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#26]/runnable@ForkJoinPool-1-worker-1, after19:49:17.033 [] INFO org.example.virtual_thread.Demo -- VirtualThread[#29]/runnable@ForkJoinPool-1-worker-2, after
            • 通过25号虚拟线程可以看出,阻塞前后使用的平台线程发生过切换
              • VirtualThread[#22]/runnable@ForkJoinPool-1-worker-2表示VirtualThread[#22]这个虚拟线程依赖于平台线程ForkJoinPool-1-worker-2,这里我在VM参数中添加了-Djdk.virtualThreadScheduler.maxPoolSize=2 -Djdk.virtualThreadScheduler.parallelism=2,限制平台线程最大2个,所以只能会看到ForkJoinPool-1-worker-1和ForkJoinPool-1-worker-2两个平台线程。
                • 虚拟线程在block后,会与平台线程解绑,然后加入任务列表排队,等待分配给平台线程

                  2. 有序集合(Sequenced Collections)

                  https://openjdk.org/jeps/431

                  • Sequenced Collections是一种具有确定出现顺序的集合。提供了处理集合第一个和最后一个元素以及反转集合的简单方法。

                    Sequenced Collections 包括以下三个接口:

                    1. SequencedCollection
                    2. SequencedSet
                    3. SequencedMap
                    interface SequencedCollection extends Collection {  // New Method  SequencedCollection reversed();  // Promoted methods from Deque  void addFirst(E);  void addLast(E);  E getFirst();  E getLast();  E removeFirst();  E removeLast();}

                    3. switch 的模式匹配(Pattern Matching for switch)

                    https://openjdk.org/jeps/441

                    • 属于语法方面的升级,增强了 switch 表达式,允许在 case 标签中使用模式。
                    • JDK21之前
                      // Prior to Java 21static String formatter(Object obj) {    String formatted = "unknown";    if (obj instanceof Integer i) {        formatted = String.format("int %d", i);    } else if (obj instanceof Long l) {        formatted = String.format("long %d", l);    } else if (obj instanceof Double d) {        formatted = String.format("double %f", d);    } else if (obj instanceof String s) {        formatted = String.format("String %s", s);    }    return formatted;}
                      • JDK21之后
                        // As of Java 21static String formatterPatternSwitch(Object obj) {    return switch (obj) {        case Integer i -> String.format("int %d", i);        case Long l    -> String.format("long %d", l);        case Double d  -> String.format("double %f", d);        case String s  -> String.format("String %s", s);        default        -> obj.toString();    };}

                        4. 记录模式(Record Patterns)

                        https://openjdk.org/jeps/440

                        • 记录模式(Record Patterns) 可对 record 的值进行解构,也就是更方便地从记录类(Record Class)中提取数据。并且,记录模式和类型模式可以嵌套使用,以实现强大的、声明性的和可组合的数据导航和处理形式。
                        • 记录模式不能单独使用,而是要与 instanceof 或 switch 模式匹配一同使用。
                          1. 以 instanceof 为例
                          // As of Java 16record Point(int x, int y) {}static void printSum(Object obj) {    if (obj instanceof Point p) {        int x = p.x();        int y = p.y();        System.out.println(x+y);    }}
                          // As of Java 21static void printSum(Object obj) {    if (obj instanceof Point(int x, int y)) {        System.out.println(x+y);    }}

                          5. ZGC

                          https://openjdk.org/jeps/439

                          • ZGC是一款低延迟、高吞吐的JVM垃圾回收器。JDK11试验版本,JDK15变为生产版本,但都是不分代的,所有的对象都存储在一起,每次垃圾回收都要回收所有对象。

                            在JDK21中区分年轻代和老年代,因为年轻代的对象存活时间更短,所以 通过提高收集年轻代的对象的频率迅速释放JVM内存。

                          • 默认不开启ZGC,可以使用以下命令开启

                            java -XX:+UseZGC -XX:+ZGenerational 

                            6. 准备禁用动态代理(Prepare to Disallow the Dynamic Loading of Agents)

                            https://openjdk.org/jeps/451

                            • 当代理被动态加载到运行中的 JVM 时发出警告。这些警告的目的是让用户做好准备,以便在未来的版本中默认禁止动态加载代理。

                              动态代理允许开发人员在运行时修改和监视Java应用程序,存在潜在的安全风险,例如窃取敏感信息、篡改数据等。因此,为了加强Java应用程序的安全性,限制动态加载代理的使用是有必要的。

                              WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warningWARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more informationWARNING: Dynamic loading of agents will be disallowed by default in a future release

上一篇:ps怎么打造飘散效果?

下一篇:Win10输入法升级全攻略,功能亮点与操作技巧详解