JDK 21 新特性详解

JDK 21 于 2023年9月19日 正式发布,是继 JDK 17 之后的第三个 LTS(长期支持)版本,支持至 2031年9月(Oracle 扩展支持至 2032年1月)。JDK 21 是 Java 历史上最重要的 LTS 版本之一,Virtual Threads(虚拟线程)Pattern Matching for switchRecord Patterns 三大特性正式标准化,同时引入了 Sequenced Collections(有序集合)String Templates(字符串模板) 预览、Generational ZGC(分代 ZGC) 等重磅特性。


目录

  1. Virtual Threads 虚拟线程正式标准化
  2. Pattern Matching for switch 正式标准化
  3. Record Patterns 记录模式正式标准化
  4. Sequenced Collections 有序集合
  5. String Templates 字符串模板(预览)
  6. Scoped Values 作用域值(预览)
  7. Structured Concurrency 结构化并发(预览)
  8. Foreign Function & Memory API(第三次预览)
  9. Vector API(第六次孵化)
  10. Key Encapsulation Mechanism API
  11. Generational ZGC 分代 ZGC
  12. 其他重要变更
  13. 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 引入了三个新接口:SequencedCollectionSequencedSetSequencedSequence,为有序集合提供了统一的访问方式。

新增接口

  • SequencedCollection<E> — 有序集合(List、Deque 等)
  • SequencedSet<E> — 有序集合(LinkedHashSet 等)
  • SequencedCollectionreversed() 方法返回逆序视图

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 的理由

  1. 长期支持,安全更新至 2031年
  2. Virtual Threads 正式标准化 — 革命性的并发模型
  3. Pattern Matching + Record Patterns 正式标准化 — 现代类型系统
  4. String Templates 预览 — 更简洁的字符串构建
  5. Sequenced Collections — 有序集合统一访问
  6. Generational ZGC — 超低延迟 GC
  7. Scoped Values + Structured Concurrency — 现代并发管理
  8. 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 是企业级应用升级的首选目标,预计将长期占据生产环境的主流版本地位。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐