文章目录
- [Java 8-21新特性系统性知识体系:聚焦JDK21 LTS四大核心特性](#Java 8-21新特性系统性知识体系:聚焦JDK21 LTS四大核心特性)
-
- 一、Java版本演进全景与LTS战略
-
- [1.1 版本时间线与LTS定位](#1.1 版本时间线与LTS定位)
- [1.2 从Java 8到21的核心演进脉络](#1.2 从Java 8到21的核心演进脉络)
- [二、Java 8-20关键特性概览(JDK21基础)](#二、Java 8-20关键特性概览(JDK21基础))
-
- [2.1 语言特性演进](#2.1 语言特性演进)
- [2.2 运行时与性能优化](#2.2 运行时与性能优化)
- [三、JDK21 LTS四大核心特性深度解析](#三、JDK21 LTS四大核心特性深度解析)
-
- [3.1 虚拟线程(Virtual Threads,JEP 444,正式特性)](#3.1 虚拟线程(Virtual Threads,JEP 444,正式特性))
-
- [3.1.1 传统平台线程的局限性](#3.1.1 传统平台线程的局限性)
- [3.1.2 虚拟线程的M:N调度模型](#3.1.2 虚拟线程的M:N调度模型)
- [3.1.3 核心API与使用方式](#3.1.3 核心API与使用方式)
- [3.1.4 适用场景与最佳实践](#3.1.4 适用场景与最佳实践)
- [3.2 模式匹配switch(Pattern Matching for switch,JEP 441,正式特性)](#3.2 模式匹配switch(Pattern Matching for switch,JEP 441,正式特性))
-
- [3.2.1 传统switch的局限性](#3.2.1 传统switch的局限性)
- [3.2.2 模式匹配switch的核心能力](#3.2.2 模式匹配switch的核心能力)
- [3.2.3 语法示例](#3.2.3 语法示例)
- [3.2.4 与记录模式结合(JEP 440,正式特性)](#3.2.4 与记录模式结合(JEP 440,正式特性))
- [3.3 结构化并发(Structured Concurrency,JEP 453,预览特性)](#3.3 结构化并发(Structured Concurrency,JEP 453,预览特性))
-
- [3.3.1 传统并发编程的问题](#3.3.1 传统并发编程的问题)
- [3.3.2 结构化并发的核心思想](#3.3.2 结构化并发的核心思想)
- [3.3.3 核心API与使用方式](#3.3.3 核心API与使用方式)
- [3.3.4 与传统方案对比](#3.3.4 与传统方案对比)
- [3.4 序列集合(Sequenced Collections,JEP 431,正式特性)](#3.4 序列集合(Sequenced Collections,JEP 431,正式特性))
-
- [3.4.1 传统集合框架的问题](#3.4.1 传统集合框架的问题)
- [3.4.2 序列集合接口体系](#3.4.2 序列集合接口体系)
- [3.4.3 核心方法](#3.4.3 核心方法)
- [3.4.4 使用示例](#3.4.4 使用示例)
- 四、JDK21其他重要特性
-
- [4.1 分代ZGC(Generational ZGC,JEP 439,正式特性)](#4.1 分代ZGC(Generational ZGC,JEP 439,正式特性))
- [4.2 字符串模板(String Templates,JEP 430,预览特性)](#4.2 字符串模板(String Templates,JEP 430,预览特性))
- [4.3 未命名模式和变量(Unnamed Patterns and Variables,JEP 443,预览特性)](#4.3 未命名模式和变量(Unnamed Patterns and Variables,JEP 443,预览特性))
- [4.4 作用域值(Scoped Values,JEP 446,预览特性)](#4.4 作用域值(Scoped Values,JEP 446,预览特性))
- 五、迁移建议与最佳实践
-
- [5.1 分阶段迁移策略](#5.1 分阶段迁移策略)
- [5.2 常见兼容性问题与解决方案](#5.2 常见兼容性问题与解决方案)
- [5.3 生产环境最佳实践](#5.3 生产环境最佳实践)
- 六、总结与未来展望
- [Java 8-21新特性面试背诵版(JDK21 LTS核心考点)](#Java 8-21新特性面试背诵版(JDK21 LTS核心考点))
-
- 一、Java版本演进与LTS战略(面试必问基础)
-
- [1.1 LTS版本时间线与核心定位(必背表格)](#1.1 LTS版本时间线与核心定位(必背表格))
- [1.2 核心演进脉络(一句话总结)](#1.2 核心演进脉络(一句话总结))
- [二、Java 8-20高频考点速记(每个版本1个核心特性)](#二、Java 8-20高频考点速记(每个版本1个核心特性))
- 三、JDK21四大核心特性(面试重中之重,占比80%)
-
- [3.1 虚拟线程(Virtual Threads,JEP 444,正式)](#3.1 虚拟线程(Virtual Threads,JEP 444,正式))
- [3.2 模式匹配switch(Pattern Matching for switch,JEP 441,正式)](#3.2 模式匹配switch(Pattern Matching for switch,JEP 441,正式))
- [3.3 结构化并发(Structured Concurrency,JEP 453,预览)](#3.3 结构化并发(Structured Concurrency,JEP 453,预览))
- [3.4 序列集合(Sequenced Collections,JEP 431,正式)](#3.4 序列集合(Sequenced Collections,JEP 431,正式))
- 四、JDK21其他高频考点
- 五、迁移与最佳实践高频考点
-
- [5.1 分阶段迁移策略(必背)](#5.1 分阶段迁移策略(必背))
- [5.2 虚拟线程最佳实践(必背)](#5.2 虚拟线程最佳实践(必背))
- 六、面试高频问答TOP10(直接背诵)
- [Java 8-21新特性一页纸速记版(考前突击专用)](#Java 8-21新特性一页纸速记版(考前突击专用))
-
- 一、LTS版本速记表(必背)
- [二、Java 8-20核心特性速记(每个版本1个词)](#二、Java 8-20核心特性速记(每个版本1个词))
- 三、JDK21四大核心特性(重中之重)
-
- [1. 虚拟线程(Virtual Threads)✅ 必考](#1. 虚拟线程(Virtual Threads)✅ 必考)
- [2. 模式匹配switch ✅ 必考](#2. 模式匹配switch ✅ 必考)
- [3. 结构化并发(预览)](#3. 结构化并发(预览))
- [4. 序列集合(Sequenced Collections)](#4. 序列集合(Sequenced Collections))
- 四、JDK21其他高频考点
- 五、迁移最佳实践速记
- 六、面试TOP5必背答案(直接说)

Java 8-21新特性系统性知识体系:聚焦JDK21 LTS四大核心特性
一、Java版本演进全景与LTS战略
1.1 版本时间线与LTS定位
Java采用"6个月一个功能版,3年一个LTS版"的发布节奏,LTS(长期支持)版本提供至少8年的官方支持,是企业级应用的首选。
| 版本 | 发布时间 | 类型 | 核心定位 | 支持周期 |
|---|---|---|---|---|
| Java 8 | 2014-03 | LTS | 函数式编程革命,生态基石 | 免费支持至2026年 |
| Java 11 | 2018-09 | LTS | 模块化成熟,云原生起步 | 免费支持至2027年 |
| Java 17 | 2021-09 | LTS | 安全高效标杆,Spring Boot 3.0最低要求 | 免费支持至2029年 |
| Java 21 | 2023-09 | LTS | 并发与语法革命,JDK8之后最重要版本 | 免费支持至2031年 |
1.2 从Java 8到21的核心演进脉络
- Java 8-11:完成模块化革命(JPMS),引入var局部变量类型推断、新HTTP Client、ZGC/Shenandoah低延迟GC
- Java 11-17:强化类型系统(密封类、记录类),完善模式匹配(instanceof),文本块转正,GC性能大幅提升
- Java 17-21:并发编程范式革命(虚拟线程、结构化并发),语法表达力飞跃(模式匹配switch、序列集合),GC进一步优化
二、Java 8-20关键特性概览(JDK21基础)
2.1 语言特性演进
- Java 8:Lambda表达式、Stream API、Optional、接口默认方法、新日期时间API
- Java 10:var局部变量类型推断
- Java 12-14:Switch表达式(预览→转正)
- Java 13-15:文本块(Text Blocks,预览→转正)
- Java 14-16:记录类(Records,预览→转正)、模式匹配instanceof(预览→转正)
- Java 15-17:密封类(Sealed Classes,预览→转正)
2.2 运行时与性能优化
- Java 9:G1 GC成为默认,引入ZGC/Shenandoah实验性GC
- Java 11:ZGC/Shenandoah转为生产可用
- Java 17:ZGC/Shenandoah性能大幅提升,支持更大堆内存
- Java 18:UTF-8成为默认字符编码
三、JDK21 LTS四大核心特性深度解析
3.1 虚拟线程(Virtual Threads,JEP 444,正式特性)
3.1.1 传统平台线程的局限性
- 1:1映射模型:每个Java线程直接对应一个操作系统内核线程
- 资源消耗巨大:每个线程默认占用约1MB栈内存,创建数千线程即消耗数GB内存
- 上下文切换昂贵:内核级线程切换需要保存/恢复大量寄存器状态
- 阻塞即浪费:线程执行I/O操作时,整个内核线程被挂起,无法执行其他任务
3.1.2 虚拟线程的M:N调度模型
虚拟线程将线程管理从操作系统上移到JVM层,实现**大量虚拟线程(M)映射到少量平台线程(N)**的调度模型:
- 载体线程(Carrier Thread):数量默认等于CPU核心数,由ForkJoinPool.commonPool管理
- 虚拟线程:轻量级执行单元,初始栈空间仅4KB,可弹性扩展
- 调度机制:虚拟线程阻塞时,JVM自动将其挂起,让出载体线程给其他就绪的虚拟线程
3.1.3 核心API与使用方式
java
// 方式1:直接创建虚拟线程
Thread.startVirtualThread(() -> System.out.println("Hello Virtual Thread!"));
// 方式2:使用Thread.Builder(推荐,可配置线程属性)
Thread.Builder builder = Thread.ofVirtual()
.name("worker-", 0)
.uncaughtExceptionHandler((t, e) -> e.printStackTrace());
Thread vThread = builder.start(() -> doWork());
// 方式3:使用ExecutorService(最适合生产环境)
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 1_000_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1)); // 模拟I/O操作
return i;
});
});
} // 自动关闭,等待所有任务完成
3.1.4 适用场景与最佳实践
- ✅ 完美适配:I/O密集型任务(REST API调用、数据库访问、文件读写、消息队列消费)
- ❌ 不适用:CPU密集型任务(视频解码、复杂数学计算)
- 最佳实践 :
- 不要池化虚拟线程(每个任务一个虚拟线程)
- 避免在虚拟线程中使用ThreadLocal(改用作用域值Scoped Values)
- 确保使用的框架和库已适配虚拟线程(Tomcat 10.1+、Spring Boot 3.2+)
3.2 模式匹配switch(Pattern Matching for switch,JEP 441,正式特性)
3.2.1 传统switch的局限性
- 只能匹配常量值(int、enum、String等)
- 不支持类型匹配
- 空值会直接抛出NullPointerException
- 复杂条件需要嵌套if-else
3.2.2 模式匹配switch的核心能力
- 类型模式:直接在case标签中进行类型检查和变量绑定
- 守卫模式(when子句):在类型匹配基础上添加额外条件
- null处理:支持case null标签,优雅处理空值
- 穷尽性检查:编译器自动检查switch是否覆盖所有可能情况
3.2.3 语法示例
java
// 传统写法(冗长且易出错)
static String classifyOld(Object obj) {
if (obj == null) {
return "null";
}
if (obj instanceof Integer i) {
if (i < 0) return "negative int";
else if (i == 0) return "zero";
else if (i % 2 == 0) return "even positive: " + i;
else return "odd positive: " + i;
}
if (obj instanceof String s) {
if (s.isBlank()) return "blank string";
else return "string: " + s;
}
return "other";
}
// Java 21模式匹配写法(简洁优雅)
static String classifyNew(Object obj) {
return switch (obj) {
case null -> "null";
case Integer i when i < 0 -> "negative int";
case Integer i when i == 0 -> "zero";
case Integer i when i % 2 == 0 -> "even positive: " + i;
case Integer i -> "odd positive: " + i;
case String s when s.isBlank() -> "blank string";
case String s -> "string: " + s;
default -> "other";
};
}
3.2.4 与记录模式结合(JEP 440,正式特性)
java
record Point(int x, int y) {}
static String describePoint(Object obj) {
return switch (obj) {
case Point(int x, int y) when x == 0 && y == 0 -> "原点";
case Point(int x, int y) when x == y -> "对角线";
case Point(int x, int y) -> "点(" + x + ", " + y + ")";
default -> "不是点";
};
}
3.3 结构化并发(Structured Concurrency,JEP 453,预览特性)
3.3.1 传统并发编程的问题
- 任务生命周期不统一:父任务结束后,子任务可能继续运行成为"孤儿线程"
- 错误处理复杂:一个子任务失败时,其他子任务仍在运行,浪费资源
- 调试困难:线程dump中无法看到任务之间的父子关系
- 代码可读性差:大量Future.get()和异常处理代码
3.3.2 结构化并发的核心思想
将多个相关的并发任务组织成父子任务结构,子任务的生命周期被严格限制在父任务的作用域内:
- 父任务等待所有子任务完成
- 任一子任务失败时,自动取消所有其他子任务
- 线程dump中清晰显示任务的层次结构
3.3.3 核心API与使用方式
java
// 场景1:所有任务必须成功(ShutdownOnFailure)
Order createOrder(Long userId, List<Long> productIds) throws ExecutionException, InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// 并行执行三个子任务
var inventoryTask = scope.fork(() -> inventoryService.deductStock(productIds));
var balanceTask = scope.fork(() -> paymentService.freezeBalance(userId, calculateTotal(productIds)));
var logTask = scope.fork(() -> logService.recordOrderCreation(userId, productIds));
// 等待所有任务完成,任一失败则取消其他任务
scope.join().throwIfFailed();
// 安全获取结果
return new Order(
inventoryTask.get(),
balanceTask.get(),
logTask.get()
);
}
}
// 场景2:最快结果优先(ShutdownOnSuccess)
String fetchDataFromMultipleSources(Long id) throws ExecutionException, InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
scope.fork(() -> cacheService.getData(id));
scope.fork(() -> databaseService.getData(id));
scope.fork(() -> externalApiService.getData(id));
// 任一任务成功则取消其他任务
return scope.join().result();
}
}
3.3.4 与传统方案对比
| 能力 | ExecutorService | CompletableFuture | StructuredTaskScope |
|---|---|---|---|
| 自动等待所有任务 | ❌ | ✅ | ✅ |
| 失败自动取消其他任务 | ❌ | ⚠️(需手动实现) | ✅ |
| 避免孤儿线程 | ❌ | ❌ | ✅ |
| 清晰的任务层次结构 | ❌ | ❌ | ✅ |
| 同步代码风格 | ❌ | ❌ | ✅ |
3.4 序列集合(Sequenced Collections,JEP 431,正式特性)
3.4.1 传统集合框架的问题
- 没有统一的接口表示"有明确顺序的集合"
- 访问首尾元素的方法不一致:
- List:get(0)、get(list.size()-1)
- Deque:getFirst()、getLast()
- LinkedHashSet:需要通过迭代器访问
- LinkedHashMap:需要通过entrySet().iterator()访问
- 反转集合需要创建新集合,效率低
3.4.2 序列集合接口体系
Java 21引入了三个新接口,统一了有序集合的操作:
Collection
└── SequencedCollection
├── List
├── Deque
└── SequencedSet
└── SortedSet
└── NavigableSet
Map
└── SequencedMap
└── SortedMap
└── NavigableMap
3.4.3 核心方法
SequencedCollection接口:
E getFirst():获取第一个元素E getLast():获取最后一个元素void addFirst(E e):在头部添加元素void addLast(E e):在尾部添加元素E removeFirst():删除并返回第一个元素E removeLast():删除并返回最后一个元素SequencedCollection<E> reversed():返回反转视图(不复制元素)
SequencedMap接口:
Map.Entry<K,V> firstEntry():获取第一个条目Map.Entry<K,V> lastEntry():获取最后一个条目Map.Entry<K,V> pollFirstEntry():删除并返回第一个条目Map.Entry<K,V> pollLastEntry():删除并返回最后一个条目V putFirst(K key, V value):在头部添加条目V putLast(K key, V value):在尾部添加条目SequencedMap<K,V> reversed():返回反转视图
3.4.4 使用示例
java
// 统一访问有序集合的首尾元素
void processFirstAndLast(SequencedCollection<String> items) {
String first = items.getFirst();
String last = items.getLast();
System.out.println("First: " + first + ", Last: " + last);
}
// 反转集合(视图,高效)
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
SequencedCollection<String> reversedList = list.reversed();
System.out.println(reversedList); // [c, b, a]
// 修改反转视图会影响原集合
reversedList.addFirst("d");
System.out.println(list); // [a, b, c, d]
// SequencedMap示例
SequencedMap<String, Integer> map = new LinkedHashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
System.out.println(map.firstEntry()); // a=1
System.out.println(map.lastEntry()); // c=3
System.out.println(map.reversed()); // {c=3, b=2, a=1}
四、JDK21其他重要特性
4.1 分代ZGC(Generational ZGC,JEP 439,正式特性)
- 将堆分为新生代和老年代,针对不同代的对象采用不同的收集策略
- 年轻代对象存活率低,收集更频繁;老年代对象存活率高,收集更少
- 相比JDK17的ZGC,吞吐量提升约25%,暂停时间仍保持在亚毫秒级
- 启用参数:
java -XX:+UseZGC -XX:+ZGenerational -jar app.jar(JDK21默认启用)
4.2 字符串模板(String Templates,JEP 430,预览特性)
- 提供更简洁、安全的字符串构建方式
- 支持在字符串字面量中嵌入表达式
- 可自定义模板处理器,防止SQL注入等安全问题
java
String name = "张三";
int age = 25;
String message = STR."姓名: \{name}, 年龄: \{age}";
// 安全SQL查询(示例)
String query = SQL."SELECT * FROM users WHERE name = \{name}";
4.3 未命名模式和变量(Unnamed Patterns and Variables,JEP 443,预览特性)
- 使用下划线
_表示未使用的变量或模式 - 提高代码可读性,消除不必要的变量声明
java
// 未命名变量
try (var _ = new Timer()) {
// 不需要引用Timer对象
}
// 未命名模式
if (obj instanceof Point(int x, _)) {
// 只关心x坐标
System.out.println("x: " + x);
}
4.4 作用域值(Scoped Values,JEP 446,预览特性)
- 虚拟线程环境下ThreadLocal的替代方案
- 更轻量、更安全,支持父子线程间的不可变数据传递
- 避免ThreadLocal在虚拟线程中的内存泄漏问题
五、迁移建议与最佳实践
5.1 分阶段迁移策略
-
阶段1:环境准备与依赖分析
- 使用
jdeprscan工具分析项目中使用的废弃API - 升级关键依赖:Spring Boot 3.2+、Tomcat 10.1+、Hibernate 6.4+、Lombok 1.18.30+
- 配置IDE支持Java 21
- 使用
-
阶段2:从Java 8升级到Java 17
- 处理javax→jakarta包名变更
- 解决模块化系统带来的反射访问限制
- 替换已移除的API(如
Thread.stop())
-
阶段3:从Java 17升级到Java 21
- 启用虚拟线程(Spring Boot:
spring.threads.virtual.enabled=true) - 逐步采用新语法特性(模式匹配switch、序列集合)
- 启用分代ZGC
- 启用虚拟线程(Spring Boot:
-
阶段4:性能优化与特性深度应用
- 重构异步代码为结构化并发
- 替换ThreadLocal为作用域值
- 优化GC参数
5.2 常见兼容性问题与解决方案
| 问题 | 解决方案 |
|---|---|
| 非法反射访问警告 | 升级依赖库至支持JPMS的版本,或临时添加--add-opens参数 |
| UTF-8默认编码 | 移除手动指定编码的冗余代码,确保文件编码为UTF-8 |
| 废弃API | 使用jdeprscan识别并替换为新API |
| 虚拟线程兼容性 | 避免在虚拟线程中使用池化技术和ThreadLocal |
5.3 生产环境最佳实践
- 新项目:直接使用Java 21 + Spring Boot 3.2+
- 老项目:先升级到Java 17稳定运行后,再考虑升级到Java 21
- 并发场景:I/O密集型任务全面使用虚拟线程,CPU密集型任务继续使用传统线程池
- 代码风格:逐步采用新语法特性,提高代码可读性和可维护性
六、总结与未来展望
Java 21是自Java 8以来最重要的LTS版本,它通过虚拟线程 彻底改变了Java并发编程的范式,通过模式匹配switch 和序列集合 大幅提升了语言的表达力,通过结构化并发简化了多任务协作的复杂性。
未来Java将继续沿着"提高生产力、简化并发编程、提升性能"的方向演进:
- Java 22-25将进一步完善虚拟线程生态
- 字符串模板、结构化并发等预览特性将逐步转正
- 继续优化GC性能,降低延迟
- 引入更多现代语言特性,如值类型、泛型改进等
对于企业和开发者来说,升级到Java 21不仅能获得显著的性能提升和开发效率改善,还能为未来5-8年的技术发展奠定坚实基础。
Java 8-21新特性面试背诵版(JDK21 LTS核心考点)
适用场景 :Java后端面试、技术评审、快速复习
核心原则 :只保留面试官最常问的定义、原理、优缺点、使用场景、代码示例,所有考点均为高频必背
一、Java版本演进与LTS战略(面试必问基础)
1.1 LTS版本时间线与核心定位(必背表格)
| 版本 | 发布时间 | 核心定位 | 企业应用现状 |
|---|---|---|---|
| Java 8 | 2014-03 | 函数式编程革命,生态基石 | 存量项目最多,即将停止免费支持 |
| Java 11 | 2018-09 | 模块化成熟,云原生起步 | 目前企业主流版本 |
| Java 17 | 2021-09 | 安全高效标杆,Spring Boot 3.0最低要求 | 快速普及中 |
| Java 21 | 2023-09 | 并发与语法革命,JDK8之后最重要版本 | 未来5-8年企业标准 |
1.2 核心演进脉络(一句话总结)
- Java 8-11:完成模块化(JPMS),引入var、新HTTP Client、ZGC/Shenandoah低延迟GC
- Java 11-17:强化类型系统(记录类、密封类),完善模式匹配(instanceof),文本块转正
- Java 17-21:并发范式革命(虚拟线程、结构化并发),语法表达力飞跃(模式匹配switch、序列集合)
二、Java 8-20高频考点速记(每个版本1个核心特性)
- Java 8:Lambda表达式、Stream API、Optional、新日期时间API(面试必问)
- Java 10:var局部变量类型推断(只能用于局部变量)
- Java 14:Switch表达式(箭头语法,返回值,无fall-through)
- Java 15 :文本块(
""",保留格式,自动处理换行) - Java 16:记录类(Records,不可变数据载体,自动生成equals/hashCode/toString)
- Java 16 :模式匹配instanceof(
if (obj instanceof String s),自动类型转换) - Java 17 :密封类(Sealed Classes,限制类的继承层次,
permits关键字)
三、JDK21四大核心特性(面试重中之重,占比80%)
3.1 虚拟线程(Virtual Threads,JEP 444,正式)
核心定义:JVM层面实现的轻量级线程,采用M:N调度模型,解决传统平台线程资源消耗大、阻塞即浪费的问题。
传统平台线程痛点(必背):
- 1:1映射内核线程,每个线程默认占用1MB栈内存
- 上下文切换昂贵(内核态切换)
- I/O阻塞时整个内核线程被挂起,资源利用率低
- 单机最多创建数千个线程
核心原理(必背):
- M:N调度:大量虚拟线程(M)映射到少量平台线程(N)
- 载体线程:数量默认等于CPU核心数,由ForkJoinPool.commonPool管理
- 挂载/卸载机制:虚拟线程阻塞时,JVM自动将其从载体线程卸载,让出资源给其他虚拟线程
- 栈内存:初始仅4KB,可弹性扩展,支持百万级并发
核心API(3种创建方式):
java
// 1. 直接创建
Thread.startVirtualThread(() -> doIO());
// 2. Thread.Builder(推荐)
Thread vThread = Thread.ofVirtual().name("worker-", 0).start(() -> doIO());
// 3. ExecutorService(生产环境首选,自动关闭)
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i=0; i<1000000; i++) {
executor.submit(() -> doIO());
}
}
适用场景(必背):
- ✅ I/O密集型任务:REST调用、数据库访问、文件读写、消息消费
- ❌ CPU密集型任务:视频解码、复杂数学计算(不会阻塞,无法发挥优势)
面试高频坑点(必背):
- 绝对不要池化虚拟线程:每个任务一个虚拟线程,池化会失去轻量级优势
- 避免使用ThreadLocal:改用作用域值(Scoped Values),防止内存泄漏
- 阻塞操作必须由JVM感知 :
Thread.sleep()、Socket.connect()等已适配,LockSupport.park()需手动处理 - 载体线程不会阻塞:虚拟线程阻塞时,载体线程会执行其他虚拟线程
- 同步块会pin载体线程 :尽量使用
java.util.concurrent.locks替代synchronized
3.2 模式匹配switch(Pattern Matching for switch,JEP 441,正式)
核心定义:扩展switch语句/表达式的能力,支持类型匹配、守卫条件、null处理和穷尽性检查,大幅简化多条件分支代码。
传统switch痛点:
- 只能匹配常量值(int、enum、String)
- 不支持类型匹配,需要嵌套if-else
- 空值直接抛NullPointerException
- 无fall-through检查,易出错
核心能力(必背):
- 类型模式:直接在case中进行类型检查和变量绑定
- 守卫模式 :
when子句添加额外条件 - null处理 :支持
case null标签 - 穷尽性检查:编译器自动检查是否覆盖所有可能情况(密封类、枚举)
核心语法示例(对比传统写法):
java
// Java 21写法(必背)
static String classify(Object obj) {
return switch (obj) {
case null -> "null"; // 优雅处理空值
case Integer i when i < 0 -> "negative"; // 类型+守卫
case Integer i -> "positive";
case String s when s.isBlank() -> "blank";
case String s -> "string: " + s;
default -> "other";
};
}
与记录模式结合(JEP 440,正式):
java
record Point(int x, int y) {}
static String describe(Point p) {
return switch (p) {
case Point(int x, int y) when x == 0 && y == 0 -> "原点";
case Point(int x, int y) when x == y -> "对角线";
case Point(int x, int y) -> "(" + x + "," + y + ")";
};
}
面试高频坑点:
- 模式匹配switch没有fall-through(箭头语法)
- 类型模式必须是可转换的,否则编译错误
- 守卫条件
when必须是布尔表达式,不能有副作用 - 对于密封类,编译器会自动检查穷尽性,不需要
default
3.3 结构化并发(Structured Concurrency,JEP 453,预览)
核心定义:将多个相关的并发任务组织成父子任务结构,子任务的生命周期严格限制在父任务的作用域内,解决传统并发的孤儿线程、错误处理复杂、调试困难等问题。
传统并发痛点(必背):
- 父任务结束后,子任务可能继续运行成为"孤儿线程"
- 一个子任务失败时,其他子任务仍在运行,浪费资源
- 线程dump中无法看到任务的父子关系
- 代码可读性差,大量Future.get()和异常处理
核心思想(必背):
并发任务的生命周期应该与代码的结构层次相对应,就像同步代码中的函数调用一样。
两种核心策略(必背):
- ShutdownOnFailure:所有任务必须成功,任一失败则取消所有其他任务
- ShutdownOnSuccess:任一任务成功则取消所有其他任务,返回最快结果
核心代码示例:
java
// ShutdownOnFailure(必背)
Order createOrder(Long userId, List<Long> productIds) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
var inventoryTask = scope.fork(() -> inventoryService.deduct(productIds));
var balanceTask = scope.fork(() -> paymentService.freeze(userId, calculateTotal(productIds)));
scope.join().throwIfFailed(); // 等待所有任务,失败则抛异常
return new Order(inventoryTask.get(), balanceTask.get());
}
}
// ShutdownOnSuccess
String fetchFastest(Long id) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
scope.fork(() -> cache.get(id));
scope.fork(() -> db.get(id));
scope.fork(() -> api.get(id));
return scope.join().result(); // 返回第一个成功的结果
}
}
与CompletableFuture对比(必背表格):
| 能力 | CompletableFuture | StructuredTaskScope |
|---|---|---|
| 自动等待所有任务 | ✅ | ✅ |
| 失败自动取消其他任务 | ❌(需手动实现) | ✅ |
| 避免孤儿线程 | ❌ | ✅ |
| 清晰的任务层次结构 | ❌ | ✅ |
| 同步代码风格 | ❌ | ✅ |
面试高频坑点:
- 结构化并发必须在try-with-resources中使用,确保scope自动关闭
fork()方法立即提交任务 ,不是在join()时才执行- 子任务抛出的异常会被包装在
ExecutionException中 - 目前是预览特性,需要添加
--enable-preview参数启用
3.4 序列集合(Sequenced Collections,JEP 431,正式)
核心定义:引入统一的接口体系表示"有明确顺序的集合",解决传统集合框架中有序集合操作不一致、访问首尾元素繁琐的问题。
传统集合痛点(必背):
- 没有统一接口表示有序集合
- 访问首尾元素方法不一致:
- List:
get(0)、get(size()-1) - Deque:
getFirst()、getLast() - LinkedHashSet/LinkedHashMap:需要通过迭代器访问
- List:
- 反转集合需要创建新集合,效率低
接口体系(必背树形结构):
Collection
└── SequencedCollection
├── List
├── Deque
└── SequencedSet
└── SortedSet
└── NavigableSet
Map
└── SequencedMap
└── SortedMap
└── NavigableMap
核心方法(必背):
- SequencedCollection :
getFirst()、getLast()、addFirst()、addLast()、removeFirst()、removeLast()、reversed()(返回视图,不复制元素) - SequencedMap :
firstEntry()、lastEntry()、pollFirstEntry()、pollLastEntry()、putFirst()、putLast()、reversed()
核心代码示例:
java
// 统一访问所有有序集合的首尾元素
void process(SequencedCollection<String> items) {
String first = items.getFirst();
String last = items.getLast();
}
// 高效反转(视图,O(1)时间复杂度)
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
SequencedCollection<String> reversed = list.reversed();
System.out.println(reversed); // [c, b, a]
// 修改视图会影响原集合
reversed.addFirst("d");
System.out.println(list); // [a, b, c, d]
面试高频坑点:
reversed()返回的是视图,不是新集合,修改会影响原集合addFirst()对于ArrayList是O(n)时间复杂度(需要移动元素)putFirst()对于LinkedHashMap是O(1),对于TreeMap是O(log n)- 不可变集合的
reversed()视图也是不可变的
四、JDK21其他高频考点
-
分代ZGC(JEP 439,正式):
- 将堆分为新生代和老年代,吞吐量提升约25%
- 暂停时间仍保持在亚毫秒级(<1ms)
- JDK21默认启用,参数:
-XX:+UseZGC -XX:+ZGenerational
-
作用域值(Scoped Values,JEP 446,预览):
- 虚拟线程环境下ThreadLocal的替代方案
- 更轻量、更安全,支持父子线程间不可变数据传递
- 避免ThreadLocal在虚拟线程中的内存泄漏问题
-
未命名模式和变量(JEP 443,预览):
- 使用下划线
_表示未使用的变量或模式 - 示例:
try (var _ = new Timer()) { ... }、case Point(int x, _) -> ...
- 使用下划线
-
字符串模板(JEP 430,预览):
- 语法:
STR."姓名: \{name}, 年龄: \{age}" - 支持自定义模板处理器,可防止SQL注入
- 语法:
五、迁移与最佳实践高频考点
5.1 分阶段迁移策略(必背)
- 环境准备 :使用
jdeprscan分析废弃API,升级关键依赖(Spring Boot 3.2+、Tomcat 10.1+) - 升级到Java 17:处理javax→jakarta包名变更,解决反射访问限制
- 升级到Java 21 :启用虚拟线程(Spring Boot:
spring.threads.virtual.enabled=true) - 深度应用:逐步采用新语法特性,重构异步代码为结构化并发
5.2 虚拟线程最佳实践(必背)
- 每个任务一个虚拟线程,不要池化
- I/O密集型任务全面使用,CPU密集型任务继续使用传统线程池
- 避免在虚拟线程中使用
synchronized同步块 - 替换ThreadLocal为作用域值
- 确保使用的框架和库已适配虚拟线程
六、面试高频问答TOP10(直接背诵)
-
Q:虚拟线程和平台线程的区别是什么?
A:平台线程是1:1映射内核线程,资源消耗大,上下文切换昂贵;虚拟线程是JVM实现的M:N调度,轻量级(初始4KB栈),支持百万级并发,阻塞时自动让出载体线程。
-
Q:为什么不能池化虚拟线程?
A:虚拟线程的创建成本极低(几乎和创建对象一样),池化会引入不必要的开销和复杂度,失去轻量级优势。每个任务一个虚拟线程是最佳实践。
-
Q:模式匹配switch相比传统switch有哪些改进?
A:支持类型匹配、守卫条件、null处理和穷尽性检查,没有fall-through,代码更简洁易读。
-
Q:结构化并发解决了什么问题?
A:解决了传统并发中的孤儿线程、错误处理复杂、调试困难等问题,将并发任务的生命周期与代码结构对应起来。
-
Q:序列集合解决了什么问题?
A:统一了有序集合的操作接口,简化了首尾元素的访问和反转操作,提高了代码的一致性和可读性。
-
Q:分代ZGC相比非分代ZGC有什么优势?
A:针对不同代的对象采用不同的收集策略,年轻代收集更频繁,老年代收集更少,吞吐量提升约25%,同时保持亚毫秒级暂停时间。
-
Q:作用域值和ThreadLocal有什么区别?
A:作用域值是不可变的,支持父子线程间传递,更轻量,不会在虚拟线程中造成内存泄漏;ThreadLocal是可变的,每个线程有自己的副本,容易泄漏。
-
Q:Java 21相比Java 17有哪些最重要的改进?
A:虚拟线程、模式匹配switch、结构化并发、序列集合、分代ZGC。
-
Q:虚拟线程适用于什么场景?不适用于什么场景?
A:适用于I/O密集型任务(REST调用、数据库访问);不适用于CPU密集型任务(视频解码、复杂计算)。
-
Q:从Java 8升级到Java 21需要注意哪些问题?
A:处理javax→jakarta包名变更,解决非法反射访问警告,替换已移除的API,升级依赖库,逐步启用新特性。
Java 8-21新特性一页纸速记版(考前突击专用)
适用场景 :面试前10分钟快速过一遍,只记数字、关键词、必背结论
核心原则:所有内容均为面试官最常问的考点,无任何冗余
一、LTS版本速记表(必背)
| 版本 | 发布时间 | 核心标签 | 企业地位 |
|---|---|---|---|
| Java 8 | 2014 | 函数式 | 存量最多 |
| Java 11 | 2018 | 模块化 | 目前主流 |
| Java 17 | 2021 | 安全 | Spring Boot 3.0+ |
| Java 21 | 2023 | 并发革命 | 未来标准 |
演进脉络:8(函数式)→11(模块化)→17(类型系统)→21(并发+语法)
二、Java 8-20核心特性速记(每个版本1个词)
- Java 8:Lambda、Stream、Optional
- Java 10:var(局部变量)
- Java 14:Switch表达式(无fall-through)
- Java 15:文本块(
""") - Java 16:记录类(Records,不可变)、模式匹配instanceof
- Java 17:密封类(Sealed,限制继承)
三、JDK21四大核心特性(重中之重)
1. 虚拟线程(Virtual Threads)✅ 必考
- 定义:JVM实现的轻量级线程,M:N调度
- 核心数字:初始栈4KB,支持百万级并发
- 载体线程:默认=CPU核心数,ForkJoinPool管理
- 适用:✅ I/O密集型(DB、API、文件)
- 禁忌:❌ CPU密集型、❌ 池化、❌ ThreadLocal
- 坑点:synchronized会pin载体线程
2. 模式匹配switch ✅ 必考
- 定义:扩展switch支持类型匹配和条件
- 核心能力:类型模式+when守卫+null处理+穷尽检查
- 语法 :
case Integer i when i<0 -> "negative" - 结合 :记录模式(
case Point(int x, int y)) - 特点:无fall-through
3. 结构化并发(预览)
- 定义:父子任务生命周期绑定
- 核心思想:并发结构=代码结构
- 两种策略 :
- ShutdownOnFailure:全成功,失败则全取消
- ShutdownOnSuccess:取最快,成功则全取消
- 解决:孤儿线程、错误处理复杂
- 使用:必须在try-with-resources中
4. 序列集合(Sequenced Collections)
- 定义:统一有序集合操作接口
- 接口体系:SequencedCollection/Set/Map
- 核心方法:getFirst()、getLast()、reversed()(视图)
- 解决:首尾元素访问不一致、反转低效
- 坑点:reversed()是视图,修改影响原集合
四、JDK21其他高频考点
- 分代ZGC:默认启用,吞吐量+25%,暂停<1ms
- 作用域值:虚拟线程替代ThreadLocal,不可变
- 未命名变量 :
_表示未使用 - 字符串模板 :
STR."姓名: \{name}"(预览)
五、迁移最佳实践速记
- 先升级到Java 17(处理javax→jakarta)
- 再升级到Java 21
- Spring Boot 3.2+:
spring.threads.virtual.enabled=true - 逐步替换:I/O密集型→虚拟线程,异步→结构化并发
六、面试TOP5必背答案(直接说)
- 虚拟线程vs平台线程:1:1 vs M:N,1MB vs 4KB,千级 vs 百万级
- 为什么不能池化虚拟线程:创建成本极低,池化失去优势
- 结构化并发解决什么问题:孤儿线程、错误处理复杂
- 序列集合解决什么问题:统一有序集合操作
- Java 21最重要改进:虚拟线程(并发范式革命)
考前最后看一眼:虚拟线程的M:N调度、4KB栈、百万级并发、I/O密集型适用、禁池化。这5个点90%的面试都会问到。