JDK 21 新特性详解
JDK 21 新特性详解
JDK 21 于 2023年9月19日 正式发布,是继 JDK 17 之后的第三个 LTS(长期支持)版本,支持至 2031年9月(Oracle 扩展支持至 2032年1月)。JDK 21 是 Java 历史上最重要的 LTS 版本之一,Virtual Threads(虚拟线程)、Pattern Matching for switch、Record Patterns 三大特性正式标准化,同时引入了 Sequenced Collections(有序集合)、String Templates(字符串模板) 预览、Generational ZGC(分代 ZGC) 等重磅特性。
目录
- Virtual Threads 虚拟线程正式标准化
- Pattern Matching for switch 正式标准化
- Record Patterns 记录模式正式标准化
- Sequenced Collections 有序集合
- String Templates 字符串模板(预览)
- Scoped Values 作用域值(预览)
- Structured Concurrency 结构化并发(预览)
- Foreign Function & Memory API(第三次预览)
- Vector API(第六次孵化)
- Key Encapsulation Mechanism API
- Generational ZGC 分代 ZGC
- 其他重要变更
- JDK 21 特性总览表
1. Virtual Threads 虚拟线程正式标准化
1.1 概述
JEP 444 — Virtual Threads(虚拟线程)在 JDK 19(首次预览)、JDK 20(第二次预览)后,终于在 JDK 21 正式标准化。虚拟线程是 Project Loom 的核心成果,是一种轻量级线程,由 JVM 管理而非操作系统。
核心特点:
- 极轻量:初始栈内存仅几百字节(平台线程约 1MB)
- 高并发:可轻松创建百万级虚拟线程
- M:N 调度:多个虚拟线程映射到少量平台线程
- 适合 IO 密集型:大量阻塞操作(数据库、网络调用)
- 与现有代码兼容:实现
Thread接口,API 不变
1.2 代码案例
// ============ 1. 创建虚拟线程 ============
// 方式1:Thread.startVirtualThread()(最简洁)
Thread vthread = Thread.startVirtualThread(() -> {
System.out.println("Hello from virtual thread!");
System.out.println("Is virtual: " + Thread.currentThread().isVirtual()); // true
});
vthread.join();
// 方式2:Thread.ofVirtual() 构建器
Thread vthread2 = Thread.ofVirtual()
.name("my-virtual-thread")
.start(() -> {
System.out.println("Thread name: " + Thread.currentThread().getName());
});
vthread2.join();
// 方式3:Thread.ofVirtual() 未启动
Thread.Builder builder = Thread.ofVirtual().name("vt-", 0);
Thread vthread3 = builder.start(() -> System.out.println("Task 1"));
Thread vthread4 = builder.start(() -> System.out.println("Task 2"));
vthread3.join();
vthread4.join();
// ============ 2. 虚拟线程执行器(最常用) ============
// 每个任务一个虚拟线程
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
// 提交大量任务
List<Future<String>> futures = IntStream.range(0, 100_000)
.mapToObj(i -> executor.submit(() -> {
Thread.sleep(Duration.ofMillis(100));
return "Task-" + i;
}))
.toList();
// 收集结果
long count = futures.stream()
.map(future -> {
try { return future.get(); }
catch (Exception e) { return null; }
})
.filter(Objects::nonNull)
.count();
System.out.println("完成: " + count + " 个任务");
}
// ============ 3. 高并发 Web 服务器 ============
public class VirtualThreadWebServer {
public static void main(String[] args) throws Exception {
try (ServerSocket serverSocket = new ServerSocket(8080)) {
System.out.println("服务器启动: http://localhost:8080");
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
while (true) {
Socket clientSocket = serverSocket.accept();
executor.submit(() -> handleClient(clientSocket));
}
}
}
}
static void handleClient(Socket socket) {
try (socket) {
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
String request = reader.readLine();
System.out.println("收到请求: " + request);
// 模拟 IO 操作(虚拟线程中阻塞不占用平台线程)
Thread.sleep(Duration.ofMillis(100));
writer.println("HTTP/1.1 200 OK");
writer.println("Content-Type: text/plain");
writer.println();
writer.println("Hello from Virtual Thread!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
// ============ 4. 并发 API 调用 ============
public class ConcurrentApiCaller {
public static void main(String[] args) {
List<String> urls = List.of(
"https://api.example.com/users",
"https://api.example.com/orders",
"https://api.example.com/products"
);
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
List<Future<String>> futures = urls.stream()
.map(url -> executor.submit(() -> callApi(url)))
.toList();
for (Future<String> future : futures) {
System.out.println(future.get());
}
} catch (Exception e) {
e.printStackTrace();
}
}
static String callApi(String url) {
// 模拟网络请求
Thread.sleep(Duration.ofMillis(500));
return "Response from " + url;
}
}
// ============ 5. 批量数据库查询 ============
public class BatchDatabaseQuery {
public static void main(String[] args) {
List<Long> userIds = LongStream.rangeClosed(1, 10_000).boxed().toList();
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
List<Future<User>> futures = userIds.stream()
.map(id -> executor.submit(() -> queryUser(id)))
.toList();
List<User> users = futures.stream()
.map(future -> {
try { return future.get(); }
catch (Exception e) { return null; }
})
.filter(Objects::nonNull)
.toList();
System.out.println("查询到 " + users.size() + " 个用户");
}
}
static User queryUser(Long id) {
// 模拟数据库查询
Thread.sleep(Duration.ofMillis(5));
return new User(id, "User-" + id);
}
record User(Long id, String name) {}
}
// ============ 6. 虚拟线程与 synchronized ============
// 注意:虚拟线程在 synchronized 块中阻塞时会固定载体线程
// 推荐使用 ReentrantLock 替代
// 不推荐(会固定载体线程)
void badExample() {
Object lock = new Object();
synchronized (lock) {
Thread.sleep(Duration.ofSeconds(1)); // 固定载体线程
}
}
// 推荐(不固定载体线程)
void goodExample() {
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
Thread.sleep(Duration.ofSeconds(1)); // 不固定载体线程
} finally {
lock.unlock();
}
}
// ============ 7. 虚拟线程与 ThreadLocal ============
// 虚拟线程可以使用 ThreadLocal,但要注意内存占用
// 推荐使用 Scoped Values(预览)替代
ThreadLocal<String> threadLocal = new ThreadLocal<>();
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 1000; i++) {
final int taskId = i;
executor.submit(() -> {
threadLocal.set("Task-" + taskId);
String value = threadLocal.get();
System.out.println(value);
threadLocal.remove(); // 及时清理
});
}
}
// ============ 8. 性能对比 ============
public class PerformanceComparison {
public static void main(String[] args) throws Exception {
int taskCount = 100_000;
// 平台线程
long start1 = System.currentTimeMillis();
try (ExecutorService platform = Executors.newFixedThreadPool(200)) {
for (int i = 0; i < taskCount; i++) {
platform.submit(() -> Thread.sleep(Duration.ofMillis(10)));
}
}
long platformTime = System.currentTimeMillis() - start1;
// 虚拟线程
long start2 = System.currentTimeMillis();
try (ExecutorService virtual = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < taskCount; i++) {
virtual.submit(() -> Thread.sleep(Duration.ofMillis(10)));
}
}
long virtualTime = System.currentTimeMillis() - start2;
System.out.println("平台线程: " + platformTime + "ms");
System.out.println("虚拟线程: " + virtualTime + "ms");
// 虚拟线程通常快 10-100 倍
}
}
// ============ 9. 实际应用场景总结 ============
// 适用场景:
// - 高并发 Web 服务(每个请求一个虚拟线程)
// - 大量数据库访问
// - 大量远程 API 调用
// - 微服务架构
// - IO 密集型任务
// 不适用场景:
// - CPU 密集型计算(使用传统线程池)
// - 需要精确控制线程数量的场景
2. Pattern Matching for switch 正式标准化
2.1 概述
JEP 441 — Pattern Matching for switch 在 JDK 17(首次预览)、JDK 18(第二次预览)、JDK 19(第三次预览)、JDK 20(第四次预览)后,终于在 JDK 21 正式标准化。
2.2 代码案例
// ============ 1. 基础 switch 模式匹配 ============
static String format(Object obj) {
return switch (obj) {
case Integer i -> "整数: " + i;
case Long l -> "长整数: " + l;
case String s -> "字符串: " + s.toUpperCase();
case Double d -> "浮点数: " + d;
case List<?> list -> "列表大小: " + list.size();
case Map<?, ?> map -> "Map 大小: " + map.size();
case null -> "null";
default -> "未知: " + obj;
};
}
// ============ 2. 带 when 条件 ============
static String classify(Object obj) {
return switch (obj) {
case Integer i when i > 100 -> "大整数: " + i;
case Integer i when i > 0 -> "正整数: " + i;
case Integer i when i == 0 -> "零";
case Integer i -> "负整数: " + i;
case String s when s.isEmpty() -> "空字符串";
case String s when s.length() < 5 -> "短字符串: " + s;
case String s -> "长字符串: " + s;
case null -> "null";
default -> "其他";
};
}
// ============ 3. 密封类 + switch 穷举检查 ============
sealed interface Shape permits Circle, Rectangle, Triangle {
double area();
}
record Circle(double radius) implements Shape {
@Override public double area() { return Math.PI * radius * radius; }
}
record Rectangle(double width, double height) implements Shape {
@Override public double area() { return width * height; }
}
record Triangle(double a, double b, double c) implements Shape {
@Override
public double area() {
double s = (a + b + c) / 2;
return Math.sqrt(s * (s - a) * (s - b) * (s - c));
}
}
// 编译器穷举检查:不需要 default
static String describe(Shape shape) {
return switch (shape) {
case Circle c -> "圆形,半径: " + c.radius();
case Rectangle r -> "矩形,宽: " + r.width() + ",高: " + r.height();
case Triangle t -> "三角形,边长: " + t.a() + ", " + t.b() + ", " + t.c();
};
}
// ============ 4. 异常处理 ============
static String handleException(Exception e) {
return switch (e) {
case SQLException sql -> "SQL 错误码: " + sql.getErrorCode();
case IOException io -> "IO 错误: " + io.getMessage();
case RuntimeException rt -> "运行时错误: " + rt.getMessage();
case Exception ex -> "通用错误: " + ex.getMessage();
};
}
// ============ 5. 实际应用场景 ============
// 5.1 命令解析
sealed interface Command permits StartCommand, StopCommand, StatusCommand, UnknownCommand {
void execute();
}
record StartCommand(String serviceName) implements Command {
@Override public void execute() { System.out.println("启动: " + serviceName); }
}
record StopCommand(String serviceName) implements Command {
@Override public void execute() { System.out.println("停止: " + serviceName); }
}
record StatusCommand() implements Command {
@Override public void execute() { System.out.println("状态查询"); }
}
record UnknownCommand(String input) implements Command {
@Override public void execute() { System.out.println("未知: " + input); }
}
static void processCommand(Command cmd) {
switch (cmd) {
case StartCommand(var name) when name.isEmpty() ->
System.out.println("服务名不能为空");
case StartCommand(var name) ->
System.out.println("启动服务: " + name);
case StopCommand(var name) when name.isEmpty() ->
System.out.println("服务名不能为空");
case StopCommand(var name) ->
System.out.println("停止服务: " + name);
case StatusCommand s ->
System.out.println("查询所有服务状态");
case UnknownCommand(var input) ->
System.out.println("未知命令: " + input);
}
}
// 5.2 JSON 值处理
sealed interface JsonValue
permits JsonString, JsonNumber, JsonBoolean, JsonNull, JsonArray, JsonObject {
}
record JsonString(String value) implements JsonValue {}
record JsonNumber(double value) implements JsonValue {}
record JsonBoolean(boolean value) implements JsonValue {}
record JsonNull() implements JsonValue {}
record JsonArray(List<JsonValue> elements) implements JsonValue {}
record JsonObject(Map<String, JsonValue> properties) implements JsonValue {}
static String renderJson(JsonValue value) {
return switch (value) {
case JsonString(var s) -> "\"" + s + "\"";
case JsonNumber(var n) -> String.valueOf(n);
case JsonBoolean(var b) -> String.valueOf(b);
case JsonNull() -> "null";
case JsonArray(var elements) ->
"[" + elements.stream()
.map(PatternMatchingDemo::renderJson)
.collect(Collectors.joining(", ")) + "]";
case JsonObject(var properties) ->
"{" + properties.entrySet().stream()
.map(e -> "\"" + e.getKey() + "\": " + renderJson(e.getValue()))
.collect(Collectors.joining(", ")) + "}";
};
}
3. Record Patterns 记录模式正式标准化
3.1 概述
JEP 440 — Record Patterns(记录模式)在 JDK 19(首次预览)、JDK 20(第二次预览)后,终于在 JDK 21 正式标准化。记录模式允许在模式匹配中解构 Record 的组件。
3.2 代码案例
// ============ 1. 基础记录模式 ============
record Point(int x, int y) {}
// instanceof 解构
void printPoint(Object obj) {
if (obj instanceof Point(int x, int y)) {
System.out.println("x=" + x + ", y=" + y);
}
}
// switch 解构
String describe(Object obj) {
return switch (obj) {
case Point(int x, int y) -> "Point: (" + x + ", " + y + ")";
default -> "Unknown";
};
}
// ============ 2. 嵌套记录模式 ============
record Line(Point start, Point end) {}
record Circle(Point center, double radius) {}
record Rectangle(Point topLeft, Point bottomRight) {}
// 嵌套解构
String describeShape(Object obj) {
return switch (obj) {
case Line(Point(var x1, var y1), Point(var x2, var y2)) ->
"线段: (" + x1 + "," + y1 + ") -> (" + x2 + "," + y2 + ")";
case Circle(Point(var x, var y), var r) ->
"圆: 圆心=(" + x + "," + y + "), 半径=" + r;
case Rectangle(Point(var x1, var y1), Point(var x2, var y2)) ->
"矩形: (" + x1 + "," + y1 + ") -> (" + x2 + "," + y2 + ")";
default -> "未知";
};
}
// ============ 3. 带条件的记录模式 ============
String classify(Object obj) {
return switch (obj) {
case Point(var x, var y) when x == 0 && y == 0 -> "原点";
case Point(var x, var y) when x == 0 -> "Y轴上";
case Point(var x, var y) when y == 0 -> "X轴上";
case Point(var x, var y) -> "普通点: (" + x + ", " + y + ")";
case Rectangle(Point(var x1, var y1), Point(var x2, var y2))
when Math.abs(x2 - x1) == Math.abs(y2 - y1) -> "正方形";
case Rectangle(Point(var x1, var y1), Point(var x2, var y2)) ->
"矩形";
default -> "未知";
};
}
// ============ 4. 实际应用场景 ============
// 4.1 领域建模
record Order(Long id, Customer customer, List<OrderItem> items, OrderStatus status) {}
record Customer(String name, String email) {}
record OrderItem(String product, int quantity, BigDecimal price) {}
enum OrderStatus { PENDING, PAID, SHIPPED, DELIVERED, CANCELLED }
String summarizeOrder(Object obj) {
return switch (obj) {
case Order(var id, Customer(var name, var email), var items, var status) ->
String.format("订单 #%d: 客户 %s (%s), %d 件商品, 状态: %s",
id, name, email, items.size(), status);
default -> "未知";
};
}
// 4.2 表达式求值
sealed interface Expr permits Constant, Var, Add, Mul {
double eval(Map<String, Double> env);
}
record Constant(double value) implements Expr {
@Override public double eval(Map<String, Double> env) { return value; }
}
record Var(String name) implements Expr {
@Override public double eval(Map<String, Double> env) { return env.get(name); }
}
record Add(Expr left, Expr right) implements Expr {
@Override public double eval(Map<String, Double> env) {
return left.eval(env) + right.eval(env);
}
}
record Mul(Expr left, Expr right) implements Expr {
@Override public double eval(Map<String, Double> env) {
return left.eval(env) * right.eval(env);
}
}
// 使用记录模式简化表达式处理
String prettyPrint(Expr expr) {
return switch (expr) {
case Constant(var value) -> String.valueOf(value);
case Var(var name) -> name;
case Add(var left, var right) ->
"(" + prettyPrint(left) + " + " + prettyPrint(right) + ")";
case Mul(var left, var right) ->
"(" + prettyPrint(left) + " * " + prettyPrint(right) + ")";
};
}
4. Sequenced Collections 有序集合
4.1 概述
JEP 431 — Sequenced Collections(有序集合)。JDK 21 引入了三个新接口:SequencedCollection、SequencedSet、SequencedSequence,为有序集合提供了统一的访问方式。
新增接口:
SequencedCollection<E>— 有序集合(List、Deque 等)SequencedSet<E>— 有序集合(LinkedHashSet 等)SequencedCollection的reversed()方法返回逆序视图
4.2 代码案例
// ============ 1. 基础用法 ============
// SequencedCollection
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
// 获取第一个和最后一个元素
String first = list.getFirst(); // "a"
String last = list.getLast(); // "c"
// 添加第一个和最后一个元素
list.addFirst("z"); // [z, a, b, c]
list.addLast("d"); // [z, a, b, c, d]
// 移除第一个和最后一个元素
list.removeFirst(); // 返回 "z",列表变为 [a, b, c, d]
list.removeLast(); // 返回 "d",列表变为 [a, b, c]
// ============ 2. 逆序视图 ============
List<String> original = List.of("a", "b", "c");
List<String> reversed = original.reversed(); // [c, b, a]
System.out.println(reversed); // [c, b, a]
// 逆序遍历
for (String s : list.reversed()) {
System.out.println(s); // c, b, a
}
// ============ 3. SequencedSet ============
Set<String> set = new LinkedHashSet<>(List.of("a", "b", "c"));
// SequencedSet 也有 getFirst/getLast/reversed
String firstSet = ((SequencedSet<String>) set).getFirst(); // "a"
String lastSet = ((SequencedSet<String>) set).getLast(); // "c"
// ============ 4. 实际应用场景 ============
// 4.1 获取队列首尾元素
Deque<String> queue = new ArrayDeque<>(List.of("task1", "task2", "task3"));
String firstTask = queue.getFirst(); // "task1"
String lastTask = queue.getLast(); // "task3"
// 4.2 逆序处理
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
for (int n : numbers.reversed()) {
System.out.println(n); // 5, 4, 3, 2, 1
}
// 4.3 通用方法
<T> void printFirstAndLast(SequencedCollection<T> collection) {
System.out.println("First: " + collection.getFirst());
System.out.println("Last: " + collection.getLast());
}
printFirstAndLast(List.of("a", "b", "c"));
printFirstAndLast(new ArrayDeque<>(List.of(1, 2, 3)));
// 4.4 逆序流
List<String> items = List.of("apple", "banana", "cherry");
items.reversed().stream()
.forEach(System.out::println); // cherry, banana, apple
5. String Templates 字符串模板(预览)
5.1 概述
JEP 430 — String Templates(字符串模板)以预览形式引入。字符串模板提供了一种更简洁、更安全的方式来构建字符串,替代 String.format() 和字符串拼接。
语法:使用 STR. 前缀和 \{} 插值。
5.2 代码案例
// ============ 1. 基础字符串模板 ============
String name = "Alice";
int age = 25;
// 传统写法
String s1 = "Hello, " + name + "! You are " + age + " years old.";
String s2 = String.format("Hello, %s! You are %d years old.", name, age);
// 字符串模板(JDK 21 预览)
String s3 = STR."Hello, \{name}! You are \{age} years old.";
System.out.println(s3); // "Hello, Alice! You are 25 years old."
// ============ 2. 表达式插值 ============
int x = 10;
int y = 20;
String result = STR."\{x} + \{y} = \{x + y}";
System.out.println(result); // "10 + 20 = 30"
// 方法调用
String upper = STR."Hello, \{name.toUpperCase()}!";
System.out.println(upper); // "Hello, ALICE!"
// 三元运算
String status = STR."Status: \{age >= 18 ? "Adult" : "Minor"}";
System.out.println(status); // "Status: Adult"
// ============ 3. 多行模板 ============
String json = STR."""
{
"name": "\{name}",
"age": \{age},
"active": true
}
""";
System.out.println(json);
// {
// "name": "Alice",
// "age": 25,
// "active": true
// }
// ============ 4. SQL 查询 ============
String userId = "123";
String status = "ACTIVE";
String sql = STR."""
SELECT * FROM users
WHERE id = '\{userId}'
AND status = '\{status}'
ORDER BY created_at DESC
""";
// ============ 5. 日志消息 ============
String level = "ERROR";
String message = "Database connection failed";
LocalDateTime time = LocalDateTime.now();
String log = STR."[\{time}] [\{level}] \{message}";
System.out.println(log);
// ============ 6. 实际应用场景 ============
// 6.1 HTML 模板
String buildHtml(String title, String content) {
return STR."""
<!DOCTYPE html>
<html>
<head><title>\{title}</title></head>
<body>
<h1>\{title}</h1>
<p>\{content}</p>
</body>
</html>
""";
}
// 6.2 配置文件
String buildConfig(String host, int port, String dbName) {
return STR."""
server:
host: \{host}
port: \{port}
database:
name: \{dbName}
url: jdbc:mysql://\{host}:\{port}/\{dbName}
""";
}
// ============ 7. 编译与运行 ============
// String templates 是预览特性
// javac --enable-preview --release 21 App.java
// java --enable-preview -cp . App
6. Scoped Values 作用域值(预览)
6.1 概述
JEP 429 — Scoped Values(作用域值)以预览形式引入,是 ThreadLocal 的现代替代方案。Scoped Values 是不可变的、可以在线程和虚拟线程之间安全共享的值。
6.2 代码案例
// ============ 1. 基础用法 ============
import java.lang.ScopedValue;
// 定义 ScopedValue
static final ScopedValue<String> USER = ScopedValue.newInstance();
// 使用 ScopedValue
void handleRequest() {
ScopedValue.where(USER, "Alice")
.run(() -> {
System.out.println("User: " + USER.get()); // "Alice"
processRequest();
});
}
void processRequest() {
System.out.println("Processing for: " + USER.get());
}
// ============ 2. 返回值 ============
static final ScopedValue<Integer> USER_ID = ScopedValue.newInstance();
int processWithReturn() {
return ScopedValue.where(USER_ID, 42)
.call(() -> {
return doWork();
});
}
int doWork() {
int userId = USER_ID.get();
return userId * 2;
}
// ============ 3. 多个 ScopedValue ============
static final ScopedValue<String> USER = ScopedValue.newInstance();
static final ScopedValue<String> REQUEST_ID = ScopedValue.newInstance();
static final ScopedValue<Locale> LOCALE = ScopedValue.newInstance();
void handleComplexRequest() {
ScopedValue.where(USER, "Alice")
.where(REQUEST_ID, "req-123")
.where(LOCALE, Locale.CHINA)
.run(() -> {
System.out.println("User: " + USER.get());
System.out.println("Request: " + REQUEST_ID.get());
System.out.println("Locale: " + LOCALE.get());
});
}
// ============ 4. 与虚拟线程配合 ============
static final ScopedValue<String> TRACE_ID = ScopedValue.newInstance();
void concurrentProcessing() {
ScopedValue.where(TRACE_ID, "trace-123")
.run(() -> {
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> {
System.out.println("Trace ID: " + TRACE_ID.get());
});
}
});
}
// ============ 5. vs ThreadLocal ============
// ThreadLocal(旧方式)
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("value");
try {
String value = threadLocal.get();
} finally {
threadLocal.remove(); // 必须手动清理
}
// ScopedValue(新方式)
ScopedValue<String> scopedValue = ScopedValue.newInstance();
ScopedValue.where(scopedValue, "value")
.run(() -> {
String value = scopedValue.get();
// 自动清理,无需手动 remove
});
// ============ 6. 实际应用场景 ============
// 请求上下文传递
public class RequestContext {
static final ScopedValue<String> USER_ID = ScopedValue.newInstance();
static final ScopedValue<String> TRACE_ID = ScopedValue.newInstance();
public static void handleRequest(String userId, String traceId, Runnable handler) {
ScopedValue.where(USER_ID, userId)
.where(TRACE_ID, traceId)
.run(handler);
}
public static String getCurrentUserId() {
return USER_ID.get();
}
}
// 使用
RequestContext.handleRequest("user-123", "trace-456", () -> {
System.out.println("User: " + RequestContext.getCurrentUserId());
});
// ============ 7. 编译与运行 ============
// Scoped Values 是预览特性
// javac --enable-preview --release 21 App.java
// java --enable-preview -cp . App
7. Structured Concurrency 结构化并发(预览)
7.1 概述
JEP 437 — Structured Concurrency(结构化并发)以预览形式引入。结构化并发将多个并发任务作为一个单元进行管理,简化了错误处理和取消操作。
7.2 代码案例
// ============ 1. 基础结构化并发 ============
import java.util.concurrent.*;
// 传统方式
void traditionalApproach() throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(2);
try {
Future<String> userFuture = executor.submit(() -> fetchUser());
Future<List<Order>> ordersFuture = executor.submit(() -> fetchOrders());
String user = userFuture.get();
List<Order> orders = ordersFuture.get();
} finally {
executor.shutdown();
}
}
// 结构化并发
void structuredApproach() throws Exception {
try (var scope = new StructuredTaskScope<Object>()) {
Subtask<String> userTask = scope.fork(() -> fetchUser());
Subtask<List<Order>> ordersTask = scope.fork(() -> fetchOrders());
scope.join();
String user = (String) userTask.get();
List<Order> orders = (List<Order>) ordersTask.get();
}
}
// ============ 2. 错误处理 ============
void structuredErrorHandling() {
try (var scope = new StructuredTaskScope<Object>()) {
Subtask<String> task1 = scope.fork(() -> riskyOperation1());
Subtask<String> task2 = scope.fork(() -> riskyOperation2());
scope.join();
String result1 = (String) task1.get();
String result2 = (String) task2.get();
} catch (Exception e) {
// scope 关闭时自动取消所有未完成的任务
System.out.println("错误: " + e.getMessage());
}
}
// ============ 3. 超时控制 ============
void withTimeout() throws Exception {
try (var scope = new StructuredTaskScope<Object>()) {
Subtask<String> task1 = scope.fork(() -> slowOperation1());
Subtask<String> task2 = scope.fork(() -> slowOperation2());
scope.joinUntil(Instant.now().plusSeconds(5));
if (task1.state() == Subtask.State.SUCCESS) {
String result = (String) task1.get();
}
}
}
// ============ 4. 实际应用场景 ============
// 并发数据获取
class UserProfile {
String name;
List<Order> orders;
List<Notification> notifications;
}
UserProfile loadUserProfile(Long userId) throws Exception {
try (var scope = new StructuredTaskScope<Object>()) {
Subtask<String> nameTask = scope.fork(() -> fetchUserName(userId));
Subtask<List<Order>> ordersTask = scope.fork(() -> fetchOrders(userId));
Subtask<List<Notification>> notificationsTask = scope.fork(() -> fetchNotifications(userId));
scope.join();
UserProfile profile = new UserProfile();
profile.name = (String) nameTask.get();
profile.orders = (List<Order>) ordersTask.get();
profile.notifications = (List<Notification>) notificationsTask.get();
return profile;
}
}
// 竞速模式
String race() throws Exception {
try (var scope = new StructuredTaskScope<String>()) {
Subtask<String> task1 = scope.fork(() -> queryServer1());
Subtask<String> task2 = scope.fork(() -> queryServer2());
Subtask<String> task3 = scope.fork(() -> queryServer3());
scope.joinUntil(Instant.now().plusSeconds(5));
if (task1.state() == Subtask.State.SUCCESS) {
return task1.get();
} else if (task2.state() == Subtask.State.SUCCESS) {
return task2.get();
} else if (task3.state() == Subtask.State.SUCCESS) {
return task3.get();
}
throw new TimeoutException("All tasks failed");
}
}
// ============ 5. 编译与运行 ============
// Structured Concurrency 是预览特性
// javac --enable-preview --release 21 App.java
// java --enable-preview -cp . App
8. Foreign Function & Memory API(第三次预览)
8.1 概述
JEP 442 — Foreign Function & Memory API 继续演进,JDK 21 进行了第三次预览。
8.2 代码案例
// ============ 1. 调用 C 标准库函数 ============
import java.lang.invoke.*;
import jdk.incubator.foreign.*;
import static jdk.incubator.foreign.ValueLayout.*;
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle strlen = linker.downcallHandle(
stdlib.lookup("strlen").orElseThrow(),
FunctionDescriptor.of(JAVA_LONG, ADDRESS)
);
try (MemorySegment str = SegmentAllocator.implicitAllocating().allocateUtf8String("Hello")) {
long length = (long) strlen.invoke(str);
System.out.println("长度: " + length); // 5
}
// ============ 2. 操作堆外内存 ============
try (MemorySegment segment = MemorySegment.allocateNative(1024)) {
MemoryAddress base = segment.baseAddress();
VarHandle intHandle = JAVA_INT.varHandle();
intHandle.set(base, 0L, 42);
int value = (int) intHandle.get(base, 0L);
System.out.println("值: " + value); // 42
}
// ============ 3. 编译与运行 ============
// javac --add-modules jdk.incubator.foreign App.java
// java --add-modules jdk.incubator.foreign App
9. Vector API(第六次孵化)
9.1 概述
JEP 448 — Vector API 继续孵化,JDK 21 进行了第六次孵化。
9.2 代码案例
// ============ 1. 基础向量操作 ============
import jdk.incubator.vector.*;
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;
void vectorAdd(float[] a, float[] b, float[] c) {
int i = 0;
for (; i < SPECIES.loopBound(a.length); i += SPECIES.length()) {
FloatVector va = FloatVector.fromArray(SPECIES, a, i);
FloatVector vb = FloatVector.fromArray(SPECIES, b, i);
va.add(vb).intoArray(c, i);
}
for (; i < a.length; i++) {
c[i] = a[i] + b[i];
}
}
// ============ 2. 编译与运行 ============
// javac --add-modules jdk.incubator.vector App.java
// java --add-modules jdk.incubator.vector App
10. Key Encapsulation Mechanism API
10.1 概述
JEP 452 — Key Encapsulation Mechanism(KEM)API。KEM 是一种公钥加密技术,用于安全地交换对称密钥。JDK 21 新增了对 KEM 的原生支持。
10.2 代码案例
// ============ 1. 基础 KEM 使用 ============
import javax.crypto.*;
import java.security.*;
// 生成密钥对
KeyPairGenerator kpg = KeyPairGenerator.getInstance("X25519");
KeyPair keyPair = kpg.generateKeyPair();
// 创建 KEM
KeyEncapsulation kem = KeyEncapsulation.getInstance("DHKEM");
kem.init(keyPair.getPublic());
// 封装(发送方)
KeyEncapsulation.Encapsulated encapsulated = kem.encapsulate();
byte[] sharedSecret = encapsulated.sharedSecret();
byte[] encapsulation = encapsulated.encapsulation();
// 解封装(接收方)
kem.init(keyPair.getPrivate());
byte[] receivedSecret = kem.decapsulate(encapsulation);
// 双方应该得到相同的共享密钥
System.out.println(Arrays.equals(sharedSecret, receivedSecret)); // true
// ============ 2. 实际应用场景 ============
// 安全密钥交换
class SecureKeyExchange {
public static byte[] establishSharedSecret(PublicKey recipientPublicKey)
throws Exception {
KeyEncapsulation kem = KeyEncapsulation.getInstance("DHKEM");
kem.init(recipientPublicKey);
KeyEncapsulation.Encapsulated result = kem.encapsulate();
// 发送 encapsulation 给接收方
// 返回 sharedSecret 用于对称加密
return result.sharedSecret();
}
public static byte[] receiveSharedSecret(byte[] encapsulation, PrivateKey privateKey)
throws Exception {
KeyEncapsulation kem = KeyEncapsulation.getInstance("DHKEM");
kem.init(privateKey);
return kem.decapsulate(encapsulation);
}
}
11. Generational ZGC 分代 ZGC
11.1 概述
JEP 439 — Generational ZGC(分代 ZGC)。JDK 21 将 ZGC 扩展为支持分代模式,进一步提升了 GC 性能。
改进:
- 分代收集(年轻代/老年代)
- 更低的暂停时间
- 更好的内存利用率
- 更高的吞吐量
11.2 使用方式
# ============ 1. 启用分代 ZGC ============
java -XX:+UseZGC -XX:+ZGenerational -jar app.jar
# ============ 2. 对比非分代 ZGC ============
# 非分代(JDK 17+)
java -XX:+UseZGC -jar app.jar
# 分代(JDK 21+)
java -XX:+UseZGC -XX:+ZGenerational -jar app.jar
# ============ 3. 性能对比 ============
# 分代 ZGC vs 非分代 ZGC:
# - 暂停时间更低(< 1ms)
# - 吞吐量更高(提升 10%-20%)
# - 内存占用更低
# ============ 4. 监控 ZGC ============
# 启用 GC 日志
java -XX:+UseZGC -XX:+ZGenerational -Xlog:gc*:file=gc.log -jar app.jar
12. 其他重要变更
12.1 其他改进
// ============ 1. 安全改进 ============
// 1. 改进了 TLS 1.3 实现
// 2. 增强了证书路径验证
// 3. 改进了 PKCS#12 密钥库处理
// 4. 新增 KEM API(JEP 452)
// ============ 2. 性能改进 ============
// 1. G1 GC 改进
// - 更好的并行标记
// - 改进的内存回收
// 2. ZGC 改进
// - 分代模式(JEP 439)
// - 更低的暂停时间
// 3. 虚拟线程优化
// - 更好的调度算法
// - 更低的内存占用
// ============ 3. 国际化 ============
// 升级到 Unicode 15.0
// 改进了 CLDR 数据
// ============ 4. 新的系统属性 ============
// jdk.virtualThreadScheduler.parallelism — 虚拟线程调度器并行度
// jdk.virtualThreadScheduler.maxPoolSize — 虚拟线程调度器最大池大小
13. JDK 21 特性总览表
| 序号 | 特性 | JEP | 类型 | 重要性 |
|---|---|---|---|---|
| 1 | Virtual Threads 正式标准化 | JEP 444 | 并发 | ★★★★★ |
| 2 | Pattern Matching for switch 正式标准化 | JEP 441 | 语言 | ★★★★★ |
| 3 | Record Patterns 正式标准化 | JEP 440 | 语言 | ★★★★★ |
| 4 | Sequenced Collections 有序集合 | JEP 431 | API | ★★★★☆ |
| 5 | String Templates 字符串模板(预览) | JEP 430 | 语言 | ★★★★★ |
| 6 | Scoped Values 作用域值(预览) | JEP 429 | 并发 | ★★★★☆ |
| 7 | Structured Concurrency 结构化并发(预览) | JEP 437 | 并发 | ★★★★★ |
| 8 | Foreign Function & Memory API(第三次预览) | JEP 442 | API | ★★★★☆ |
| 9 | Vector API(第六次孵化) | JEP 448 | API | ★★★☆☆ |
| 10 | Key Encapsulation Mechanism API | JEP 452 | 安全 | ★★★★☆ |
| 11 | Generational ZGC 分代 ZGC | JEP 439 | GC | ★★★★★ |
附录:预览特性状态追踪
| 特性 | JDK 12-16 | JDK 17 | JDK 18 | JDK 19 | JDK 20 | JDK 21 |
|---|---|---|---|---|---|---|
| Pattern Matching switch | 预览 | 预览 | 第二次预览 | 第三次预览 | 第四次预览 | 正式 |
| Record Patterns | — | — | — | 预览 | 第二次预览 | 正式 |
| Virtual Threads | — | — | — | 预览 | 第二次预览 | 正式 |
| String Templates | — | — | — | — | — | 预览 |
| Scoped Values | — | — | — | — | 孵化 | 预览 |
| Structured Concurrency | — | — | — | 孵化 | 第二次孵化 | 预览 |
附录:JDK 21 作为 LTS 的重要性
| 项目 | 说明 |
|---|---|
| 发布日期 | 2023年9月19日 |
| 支持期限 | 至 2031年9月(Oracle 扩展至 2032年1月) |
| 前一个 LTS | JDK 17(2021年9月) |
| 下一个 LTS | JDK 25(2025年9月) |
| 企业升级目标 | JDK 8/11/17 → JDK 21 |
升级到 JDK 21 的理由:
- 长期支持,安全更新至 2031年
- Virtual Threads 正式标准化 — 革命性的并发模型
- Pattern Matching + Record Patterns 正式标准化 — 现代类型系统
- String Templates 预览 — 更简洁的字符串构建
- Sequenced Collections — 有序集合统一访问
- Generational ZGC — 超低延迟 GC
- Scoped Values + Structured Concurrency — 现代并发管理
- KEM API — 现代密码学支持
总结:JDK 21 是 Java 历史上最重要的 LTS 版本之一。Virtual Threads、Pattern Matching for switch、Record Patterns 三大特性正式标准化,标志着 Java 语言进入现代化新阶段;String Templates 预览为字符串构建提供了更优雅的方式;Sequenced Collections 统一了有序集合的访问方式;Generational ZGC 将 GC 暂停时间降至 1ms 以下;Scoped Values + Structured Concurrency 为并发编程提供了更安全的方式。作为 LTS 版本,JDK 21 是企业级应用升级的首选目标,预计将长期占据生产环境的主流版本地位。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)