一文详细盘点JDK21的新特性

 更新时间:2026年07月18日 09:06:53   作者:zhangjw34  
JDK21是Java的重要长期支持(LTS)版本,这篇文章主要介绍了JDK21新特性的相关资料,文中通过代码介绍的非常详细,对大家学习或者使用jdk具有一定的参考借鉴价值,需要的朋友可以参考下

前言

Java作为企业级开发的主流语言,其每一个LTS版本的发布都备受关注——JDK21就是继JDK17之后的又一个重要长期支持版本,于2023年9月正式发布,Oracle承诺提供至少8年技术支持,共包含15个新特性,覆盖语言语法、并发编程、垃圾回收、API扩展等多个核心维度,既能提升开发效率,又能优化程序性能,堪称“兼顾稳定性与创新性”的里程碑版本。

今天就带大家全面盘点JDK21的核心新特性,结合代码示例和实战场景,帮大家快速掌握这些新功能,轻松应用到实际开发中(所有代码均基于JDK21环境编写,预览特性需添加--enable-preview参数编译运行)。

一、核心正式特性(可直接用于生产环境)

1. 虚拟线程(Virtual Threads,JEP 444)—— 高并发编程的范式革命

虚拟线程是JDK21最受关注的核心特性,也是唯一晋升为正式特性的重大突破,彻底重构了Java的并发编程模型,专门解决传统平台线程的痛点。

传统平台线程(Platform Thread)依赖操作系统内核调度,每个线程需占用约1MB栈空间,上下文切换开销大,导致单机并发上限仅数千级,在I/O密集型场景(如接口调用、数据库操作、文件读写)中,大量线程处于阻塞状态,资源利用率极低。

而虚拟线程是JVM管理的轻量级用户态线程,无需操作系统内核参与调度,每个仅需几KB栈空间,单个JVM可轻松创建数百万个虚拟线程,且阻塞时会自动挂起,释放载体线程资源,充分利用CPU时间,从根本上提升高并发场景的吞吐量。

核心优势:轻量级、低开销、易迁移(现有线程相关代码无需修改即可兼容)、无规模限制。

4种创建方式(推荐第三种线程池方式):

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

public class VirtualThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        // 方式1:直接创建(最简单)
        Thread.startVirtualThread(() -> {
            System.out.println("方式1:虚拟线程运行中,线程类型:" + Thread.currentThread().getClass().getSimpleName());
            try {
                TimeUnit.MILLISECONDS.sleep(100); // 模拟I/O操作
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("方式1:虚拟线程执行完毕");
        });

        // 方式2:通过Thread.Builder构建(可自定义线程名称)
        Thread virtualThread = Thread.ofVirtual()
                .name("virtual-thread-2")
                .unstarted(() -> {
                    System.out.println("方式2:虚拟线程运行中,线程名称:" + Thread.currentThread().getName());
                    try {
                        TimeUnit.MILLISECONDS.sleep(150);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println("方式2:虚拟线程执行完毕");
                });
        virtualThread.start();

        // 方式3:通过线程池创建(推荐,适合批量管理并发任务)
        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < 5; i++) {
                int taskId = i;
                executor.submit(() -> {
                    System.out.println("方式3:虚拟线程任务" + taskId + "运行中,线程ID:" + Thread.currentThread().threadId());
                    try {
                        TimeUnit.MILLISECONDS.sleep(200);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println("方式3:虚拟线程任务" + taskId + "执行完毕");
                });
            }
        } // try-with-resources自动关闭线程池,无需手动shutdown

        // 方式4:通过ThreadFactory创建(灵活定制线程属性)
        ThreadFactory factory = Thread.ofVirtual()
                .name("custom-virtual-thread-", 0) // 名称前缀+自增ID
                .factory();
        Thread customThread = factory.newThread(() -> {
            System.out.println("方式4:自定义虚拟线程运行中,线程名称:" + Thread.currentThread().getName());
            try {
                TimeUnit.MILLISECONDS.sleep(250);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("方式4:自定义虚拟线程执行完毕");
        });
        customThread.start();

        // 等待所有虚拟线程执行完毕(仅用于演示)
        TimeUnit.SECONDS.sleep(2);
    }
}

避坑提示:避免在虚拟线程中使用synchronized和Thread.sleep(),会阻塞载体线程;谨慎使用ThreadLocal,虚拟线程生命周期短,易引发内存泄漏,建议显式清除。

2. 模式匹配增强(JEP 440 + JEP 441)—— 简化类型判断与数据解构

JDK21完善了模式匹配体系,将Record模式和switch模式匹配升级为正式特性,彻底替代冗长的类型判断代码,提升代码可读性和健壮性。

(1)Record模式(JEP 440)

允许在instanceof和switch中直接解构Record类实例,无需手动调用getter方法,轻松提取字段并绑定变量,适用于数据导航和处理场景。

// 定义Record类
record Point(int x, int y) {}
record Circle(Point center, int radius) {}

public class RecordPatternDemo {
    public static void main(String[] args) {
        Object obj = new Circle(new Point(3, 4), 5);
        // 嵌套解构Record实例
        if (obj instanceof Circle(Point(int x, int y), int radius)) {
            System.out.printf("圆心坐标:(%d,%d),半径:%d%n", x, y, radius);
            System.out.printf("圆心到原点距离:%d%n", (int) Math.sqrt(x*x + y*y));
        }
    }
}

说明:Record模式支持嵌套,可递归解构复杂数据,相比传统的类型强制转换+getter调用,代码简洁度提升显著。

(2)switch模式匹配(JEP 441)

将switch从“值匹配”升级为“模式匹配”,支持类型模式、空值匹配、守卫子句,且编译器会检查模式穷尽性,避免遗漏分支,同时允许switch作为表达式返回值。

public class SwitchPatternDemo {
    public static String formatObj(Object obj) {
        // switch作为表达式,支持多模式分支和守卫子句
        return switch (obj) {
            case null -> "参数为null";
            case Integer i -> STR."整数类型:\{i}";
            case Long l -> STR."长整数类型:\{l}";
            case Double d when d > 0 -> STR."正数小数:\{d}";
            case Double d -> STR."负数小数:\{d}";
            case String s -> STR."字符串类型:\{s}(长度:\{s.length()})";
            default -> STR."未知类型:\{obj.getClass().getSimpleName()}";
        };
    }

    public static void main(String[] args) {
        System.out.println(formatObj(100));
        System.out.println(formatObj(-3.14));
        System.out.println(formatObj("JDK21"));
        System.out.println(formatObj(null));
    }
}

说明:JDK21中移除了switch模式匹配中的括号模式,允许枚举常量作为case常量,进一步规范了语法。

3. 分代ZGC(Generational ZGC,JEP 439)—— 低延迟GC的性能跃升

ZGC自JDK11引入以来,以“亚毫秒级停顿”著称,但早期版本未区分对象年龄,导致老年代对象过早晋升、年轻代对象被错误回收,影响GC吞吐量。

JDK21的分代ZGC首次引入“年轻代/老年代”概念,通过追踪对象分配代际,实现更精准的回收策略:年轻代采用高频、快速回收,优先清理短命对象;老年代采用延迟回收、并发标记增强,减少不必要的GC开销。

核心优势:保持ZGC原有特性(全并发、TB级堆支持、亚毫秒级停顿)的同时,GC总体吞吐损耗降低30%~50%,堆内存利用率显著提升,尤其适合混合读写、缓存密集型、实时数据流等企业级场景。

启用方式(JVM参数):

# 启用分代ZGC
java -XX:+UseZGC -XX:+ZGenerational YourApplication
# 查看GC日志(验证分代回收)
java -XX:+UseZGC -XX:+ZGenerational -XX:+PrintGC -XX:+PrintGCDetails YourApplication

4. 序列集合(Sequenced Collections,JEP 431)—— 统一有序集合操作接口

在JDK21之前,Java的有序集合(如LinkedList、LinkedHashSet、LinkedHashMap)缺乏统一的操作接口,获取首尾元素、反转集合等操作需要依赖具体实现类,代码复用性差。

JDK21新增3个核心接口,统一了有序集合的操作规范:

  • SequencedCollection:有序集合的顶层接口,提供addFirst()、addLast()、getFirst()、getLast()、reversed()等方法;

  • SequencedSet:有序不可重复集合,继承自SequencedCollection;

  • SequencedMap:有序键值对集合,提供firstEntry()、lastEntry()、reversedMap()等方法。

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.SequencedCollection;
import java.util.SequencedMap;

public class SequencedCollectionDemo {
    public static void main(String[] args) {
        // SequencedCollection示例
        SequencedCollection<String> coll = new LinkedHashSet<>();
        coll.addFirst("JDK21");
        coll.add("新特性");
        coll.addLast("盘点");
        System.out.println("原始集合:" + coll);
        System.out.println("反转集合:" + coll.reversed());
        System.out.println("首元素:" + coll.getFirst());

        // SequencedMap示例
        SequencedMap<Integer, String> map = new LinkedHashMap<>();
        map.put(1, "虚拟线程");
        map.put(2, "分代ZGC");
        map.putLast(3, "序列集合");
        System.out.println("首键值对:" + map.firstEntry());
        System.out.println("尾键值对:" + map.lastEntry());
        System.out.println("反转Map:" + map.reversedMap());
    }
}

二、重要预览特性(需开启预览模式,未来可能优化)

预览特性需要在编译和运行时添加--enable-preview参数(如:javac --enable-preview -source 21 Demo.java;java --enable-preview Demo),虽不建议直接用于生产,但可提前了解其设计思路,为后续升级做准备。

1. 字符串模板(String Templates,JEP 430)—— 终结字符串拼接痛点

替代传统的“+”拼接和String.format(),支持在字符串中嵌入任意表达式,配合模板处理器实现语法检查、格式化、安全校验,兼顾简洁性和安全性。

JDK21提供3种内置模板处理器:

  • STR:基础插值处理器,自动转义特殊字符,适合普通字符串拼接;

  • FORMAT:格式化处理器,支持printf风格的格式控制;

  • RAW:原始处理器,不进行插值和转义,适合正则、代码生成等场景。

public class StringTemplateDemo {
    public static void main(String[] args) {
        String name = "Java开发者";
        int age = 30;
        double pi = 3.1415926;

        // STR处理器:基础插值
        String info = STR."大家好,我是\{name},今年\{age}岁,π≈\{pi}";
        // FORMAT处理器:格式化
        String formattedPi = FMT."π精确到两位小数:%.2f\{pi}";
        // RAW处理器:原始输出(不插值)
        String raw = RAW."数值:\{pi}";

        System.out.println(info);
        System.out.println(formattedPi);
        System.out.println(raw);
    }
}

优势:相比传统方式,字符串模板具备编译期语法检查、IDE实时高亮、SQL注入防护(配合自定义SQL处理器)等能力,代码更简洁、更安全。

2. 外部函数和内存API(JEP 442,第三次预览)—— 安全替代JNI

作为Project Panama的核心成果,该API旨在安全、高效地替代JNI(Java Native Interface),允许Java代码直接调用本地库(如C/C++ DLL/SO)、访问非堆内存(如GPU显存、硬件寄存器),且全程受JVM内存安全约束。

核心优势:API更简洁、异常更明确、性能更优(零拷贝、直接寄存器传参)、调试更友好,避免JNI的安全隐患和复杂配置,适用于高性能计算、机器学习、音视频编解码等场景。

import java.lang.foreign.Linker;
import java.lang.foreign.SymbolLookup;
import java.lang.foreign.FunctionDescriptor;
import java.lang.invoke.MethodHandle;

public class ForeignFunctionDemo {
    public static void main(String[] args) throws Throwable {
        // 获取本地链接器
        Linker linker = Linker.nativeLinker();
        // 查找本地库中的strlen函数
        SymbolLookup stdlib = linker.defaultLookup();
        MethodHandle strlen = linker.downcallHandle(
                stdlib.find("strlen").orElseThrow(),
                FunctionDescriptor.of(JAVA_LONG, ADDRESS)
        );

        // 调用本地strlen函数,计算字符串长度
        try (var scope = Arena.ofConfined()) {
            String str = "JDK21 Foreign API";
            long length = (long) strlen.invokeExact(scope.allocateUtf8String(str));
            System.out.println("字符串长度:" + length);
        }
    }
}

3. 其他预览特性

  • 未命名模式和变量(JEP 443):用下划线“_”作为占位符,忽略无关的匹配项或未使用的变量,简化代码(如:instanceof Point(int _, int y));

  • 未命名类和实例main方法(JEP 445):简化单类程序的编写,允许无类名声明,main方法无需static修饰,降低初学者入门门槛;

  • 结构化并发(JEP 453):引入StructuredTaskScope,统一管理子任务的生命周期,解决异步编程中的“作用域泄漏”和“错误传播失序”问题,与虚拟线程天然契合。

三、其他值得关注的更新

  • 密钥封装机制(KEM,JEP 452):新增API支持密钥封装机制,增强非对称加密的安全性,适用于密码学相关场景;

  • 向量API(JEP 448,第六次孵化):通过Vector类型与泛型运算符实现跨平台SIMD加速,提升数值计算性能;

  • 清理技术债:弃用Windows 32位端口、禁止动态代理加载不安全类,加固安全基线;

  • 时区数据更新:集成IANA时区数据2023c,修复多个时区相关问题。

四、总结与升级建议

JDK21作为LTS版本,其新特性并非简单的功能叠加,而是围绕“开发提效、性能优化、安全加固”三大核心,针对性解决了Java开发中的痛点:虚拟线程重塑并发编程模式,分代ZGC突破GC性能瓶颈,模式匹配和字符串模板简化代码编写,外部函数API打通本地交互壁垒。

升级建议:

  1. I/O密集型应用(如Web后端、微服务网关):优先升级,充分利用虚拟线程提升吞吐量;

  2. 大型企业级应用:可先在测试环境验证分代ZGC和虚拟线程,逐步迁移生产;

  3. 预览特性:暂不用于生产,可在测试环境探索,等待正式版本发布后再落地;

  4. 升级前注意兼容性:JDK21移除了部分过时API,需提前检查项目依赖,避免迁移风险。

Java的演进始终围绕“简化开发、提升性能”,JDK21的这些新特性,让Java在云原生、高并发、大数据时代依然保持强大的竞争力。建议大家尽快上手实践,将新特性融入实际开发,提升开发效率和程序质量。

到此这篇关于JDK21新特性的文章就介绍到这了,更多相关JDK21新特性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot+thymeleaf+mybatis实现甘特图的详细过程

    springboot+thymeleaf+mybatis实现甘特图的详细过程

    这篇文章主要介绍了springboot+thymeleaf+mybatis实现甘特图的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-07-07
  • idea使用tomcat报404的问题及解决过程

    idea使用tomcat报404的问题及解决过程

    解决Tomcat部署问题:检查路径是否正确(JSP文件避免放在WEB-INF)、确保Tomcat配置路径一致,必要时重新部署,若日志乱码,修改logging.properties中编码为GBK
    2025-08-08
  • Java中线程死亡的几种情况实例分析

    Java中线程死亡的几种情况实例分析

    线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。下面这篇文章主要给大家介绍了Java线程死亡的几种情况,需要的朋友可以参考下。
    2017-01-01
  • Java使用JDBC连接Oracle_MSSQL实例代码

    Java使用JDBC连接Oracle_MSSQL实例代码

    这篇文章主要介绍了Java使用JDBC连接Oracle_MSSQL实例代码,需要的朋友可以参考下
    2014-01-01
  • BaseDao封装JavaWeb的增删改查的实现代码

    BaseDao封装JavaWeb的增删改查的实现代码

    Basedao 是一种基于数据访问对象(Data Access Object)模式的设计方法,它是一个用于处理数据库操作的基础类,负责封装数据库访问的底层操作,提供通用的数据库访问方法,本文给大家介绍了BaseDao封装JavaWeb的增删改查的实现代码,需要的朋友可以参考下
    2024-03-03
  • Java深入浅出数组的定义与使用下篇

    Java深入浅出数组的定义与使用下篇

    数组是有序的元素序列,若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式
    2022-03-03
  • 如何基于java实现Gauss消元法过程解析

    如何基于java实现Gauss消元法过程解析

    这篇文章主要介绍了如何基于java实现Gauss消元法过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • Jmeter压力测试简单教程(包括服务器状态监控)

    Jmeter压力测试简单教程(包括服务器状态监控)

    Jmeter是一个非常好用的压力测试工具。Jmeter用来做轻量级的压力测试,非常合适,本文详细的介绍了Jmeter的使用,感性的可以了解一下
    2021-11-11
  • Maven下 mybatis-generator使用

    Maven下 mybatis-generator使用

    这篇文章主要介绍了Maven下 mybatis-generator使用 ,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-09-09
  • mybatis-plus 返回部分字段的解决方式

    mybatis-plus 返回部分字段的解决方式

    这篇文章主要介绍了mybatis-plus 返回部分字段的解决方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10

最新评论