JDK 21 是继 17 之后的第三个新制度 LTS,也是"现代 Java 真正成熟"的里程碑。它把酝酿了四年的虚拟线程正式转正,配合分代 ZGC、分代 Shenandoah、密钥增强、序列集合(SequencedCollection)等,一口气补齐了并发、内存、集合三大短板。如果说 JDK 8 定义了"现代写法",那 JDK 21 定义了"现代并发"。
这一篇是重点:讲清虚拟线程转正后的正式写法、它到底改写了什么、以及同版其他关键特性。读完你会明白为什么说"21 之后,并发代码可以重写一遍"。
一、虚拟线程正式版(JDK 21)
预览了 19、20 两个版本,JDK 21 把虚拟线程正式定稿,不再需要--enable-preview。API 与预览期一致,但更稳定、性能更好:
// 正式写法,直接跑try(varexecutor=Executors.newVirtualThreadPerTaskExecutor()){List<Future<Result>>futures=tasks.stream().map(t->executor.submit(()->process(t))).toList();// 每个任务一个虚拟线程,百万级并发也无压力}正式版的关键改进
- 调度器成熟:载体线程用 JDK 自带的
ForkJoinPool(按 CPU 核数),虚拟线程挂载/卸载开销进一步降低。 ThreadAPI 增强:虚拟线程有自己的Thread.Builder(ofVirtual()),且Thread.isVirtual()可区分。虚拟线程join/sleep不再阻塞载体。await/sleep语义:Thread.sleep(Duration.ZERO)在虚拟线程里会让出,不再空转;Object.wait也是挂载点。synchronized的 pin 仍在:正式版仍建议热路径用ReentrantLock;但 JVM 做了部分优化,短synchronized影响可接受。
一套对比:传统 vs 虚拟线程
// 传统:线程池 + 异步,受并发数限制ExecutorServicepool=Executors.newFixedThreadPool(200);List<Future<X>>fs=urls.stream().map(u->pool.submit(()->fetch(u)))// 最多 200 并发.toList();// 虚拟线程:每个 URL 一个线程,写法同步却并发百万try(varvt=Executors.newVirtualThreadPerTaskExecutor()){List<Future<X>>fs2=urls.stream().map(u->vt.submit(()->fetch(u)))// 不卡并发数.toList();}差异本质:前者用"少线程 + 异步"对抗阻塞,后者用"多虚拟线程 + 同步"吸收阻塞。代码量相近,但后者吞吐高几个数量级、可读性更好。
二、SequencedCollection:集合有了"首尾顺序"接口
集合框架这么多年一直缺一个"有序集合"的统一接口——List有顺序但SortedSet的"首尾"没有统一方法。JDK 21 新增SequencedCollection(及其子接口SequencedSet、SequencedMap):
SequencedCollection<String>seq=newArrayList<>();seq.addFirst("a");// 新:统一的首尾操作seq.addLast("z");Stringfirst=seq.getFirst();Stringlast=seq.getLast();SequencedCollection<String>reversed=seq.reversed();// 反向视图,O(1)// Map 也有SequencedMap<String,Integer>map=newLinkedHashMap<>();map.putFirst("k1",1);map.lastEntry();// 拿到最后一项好处:以前LinkedHashMap拿"第一个/最后一个"得自己绕;现在reversed()还能 O(1) 拿到反向视图,处理 LRU、按插入序遍历更顺。这是集合框架十多年来第一次新增顶层接口族。
三、分代 ZGC 正式
前文提过,JDK 21 把**分代 ZGC(Generational ZGC)**转正为默认 ZGC 模式:
- 对象分年轻代/老年代,只频繁回收年轻代,回收效率与内存占用大幅优化。
- 暂停时间仍 <10ms,且与堆大小无关。
- 相比 15 的单代 ZGC,吞吐更高、内存更省,生产可用性拉满。
java-XX:+UseZGC-Xmx32gApp# 默认即分代 ZGC(21)低延迟、大堆服务(网关、交易、实时计算)直接受益,几乎零调参。同版的分代 Shenandoah也转正,给用户多一个低停顿选择。
四、switch 模式匹配增强(正式)
JDK 21 把"模式匹配的 switch"正式转正,并支持类型模式 + 守卫(when):
staticStringclassify(Objecto){returnswitch(o){caseIntegeri when i>0->"正整数 "+i;caseIntegeri->"非正整 "+i;caseStrings->"字符串 "+s.length();casePoint(intx,inty)->"点 ("+x+","+y+")";// 记录解构模式casenull->"null";// 可匹配 nulldefault->"其他";};}亮点:
- 记录解构模式:
case Point(int x, int y)直接拆出 record 组件。 - 守卫
when:在模式后再加条件,细化分支。 null可匹配:显式处理 null,避免 NPE。- 配合
sealed类型可省default(穷尽)。
这套模式匹配让"基于类型的分发"从冗长if-else instanceof变成声明式、编译器可校验安全的switch。
五、其他正式/增强特性
| 特性 | 状态 | 说明 |
|---|---|---|
| 字符串模板(String Templates) | 预览 | 用STR."..."安全拼接,防注入(后续版调整,见 22/23) |
| 作用域值 ScopedValue | 预览(incubator→preview) | 替代 thread-local,配合虚拟线程 |
未命名变量/模式_ | 预览 | for (var _ : list)表示忽略 |
| 密钥派生 API(KDF) | 正式 | 现代加密派生 |
| 外部函数与内存 | 正式(Panama) | 安全高效调本地代码,替代 JNI |
| 序列化集合/分代 GC | 正式 | 见上 |
六、为什么 JDK 21 值得作为"新基线"
把 JDK 21 的能力列成升级理由:
- LTS:长期支持,框架生态全面认证(Spring Boot 3.2+ 推荐 21)。
- 虚拟线程正式:并发写法范式转移,吞吐与可读性双升。
- 分代 ZGC/Shenandoah 正式:低延迟大堆开箱即用。
- 模式匹配 + record + sealed 成熟:代码更短更安全的类型分发。
- Panama 外部函数内存正式:本地互操作不再依赖脆弱的 JNI。
- SequencedCollection:集合框架补上顺序缺口。
2026 年建议:新项目直接 21;从 8/11/17 升级,21 是"最现代且受支持"的 LTS。迁移注意强封装(17 已要求)、依赖库版本。
七、本篇记住的清单
- 虚拟线程 JDK 21正式转正,免
--enable-preview;热路径仍用ReentrantLock避 pin。 - 虚拟线程 = "多虚拟线程 + 同步写法"吸收阻塞,吞吐远超线程池 + 异步。
SequencedCollection新增统一首尾操作与reversed()视图(集合框架首次新顶层接口)。- 分代 ZGC 正式且默认低延迟;分代 Shenandoah 同期转正。
- switch 模式匹配正式:支持记录解构、
when守卫、null匹配、sealed 穷尽。 - Panama 外部函数内存 API 正式,替代 JNI。
- JDK 21 = 现代并发 + 低延迟 GC + 安全类型分发的新基线 LTS。