Java 21 新特性:虚拟线程与结构化并发实战

1. 虚拟线程(Virtual Threads)

概念:轻量级线程,由 JVM 管理而非操作系统,显著降低创建和切换开销。
优势

  • 支持百万级线程并发
  • 简化高吞吐量 I/O 密集型应用
  • 兼容传统 Thread API

实战示例:创建虚拟线程

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    // 提交多个并发任务
    executor.submit(() -> processTask("Task1"));
    executor.submit(() -> processTask("Task2"));
}

void processTask(String name) {
    System.out.println(Thread.currentThread() + " 执行: " + name);
}

输出

VirtualThread[#1]/runnable@ForkJoinPool-1-worker-1 执行: Task1  
VirtualThread[#2]/runnable@ForkJoinPool-1-worker-2 执行: Task2


2. 结构化并发(Structured Concurrency)

概念:通过父子任务关系管理并发生命周期,确保任务组合的可靠性和可观测性。
核心类StructuredTaskScope(需导入 jdk.incubator.concurrent 模块)
优势

  • 自动传播错误和取消信号
  • 避免线程泄漏
  • 简化资源清理

实战示例:并行请求聚合

try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    // 创建子任务
    Future<String> userTask = scope.fork(() -> fetchUserData());
    Future<String> orderTask = scope.fork(() -> fetchOrderData());

    scope.join();          // 等待所有子任务完成
    scope.throwIfFailed(); // 检查异常

    // 合并结果
    String result = "用户: " + userTask.resultNow() + " | 订单: " + orderTask.resultNow();
    System.out.println(result);
}

String fetchUserData() throws InterruptedException {
    Thread.sleep(500); // 模拟网络延迟
    return "张三";
}

String fetchOrderData() throws InterruptedException {
    Thread.sleep(300);
    return "订单#1001";
}

输出

用户: 张三 | 订单: 订单#1001


3. 综合实战:虚拟线程 + 结构化并发

场景:并行处理文件下载和日志记录,任一失败则整体取消。

void downloadAndLog(String url, String logPath) {
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        // 虚拟线程执行下载
        Future<byte[]> downloadTask = scope.fork(() -> {
            try (InputStream in = new URL(url).openStream()) {
                return in.readAllBytes();
            }
        });

        // 虚拟线程执行日志
        Future<Void> logTask = scope.fork(() -> {
            Files.writeString(Path.of(logPath), "开始下载: " + url);
            return null;
        });

        scope.join();
        scope.throwIfFailed();

        System.out.println("下载完成! 大小: " + downloadTask.resultNow().length + " 字节");
    } catch (Exception e) {
        System.err.println("任务失败: " + e.getMessage());
    }
}

关键点

  1. 任一子任务失败时,ShutdownOnFailure 自动取消其他任务
  2. 虚拟线程优化 I/O 阻塞操作
  3. 资源通过 try-with-resources 自动释放

4. 性能对比

传统线程池 vs 虚拟线程(10,000 个并发任务):

指标 平台线程池 虚拟线程
内存占用 $\approx$ 1GB $\approx$ 20MB
创建时间 $\approx$ 2s $\approx$ 0.1s
CPU 利用率

5. 使用建议
  1. 适用场景
    • 高并发微服务(如 HTTP 服务器)
    • 批量数据处理
    • 并行 I/O 操作
  2. 避坑指南
    • 避免在计算密集型任务中使用
    • 勿用 synchronized 阻塞虚拟线程
    • 启用预览特性:javac --release 21 --enable-preview Main.java

通过虚拟线程和结构化并发,Java 21 将并发编程复杂度从系统级降至应用级,大幅提升开发效率与可维护性。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐