JDK 21中的结构化并发:并发编程的一大进步

JEP 453: Structured Concurrency (Preview) 集成至 JDK 21

JEP 453 已从目标状态集成到 JDK 21 中,作为预览功能。该功能此前经历了两个孵化阶段:JDK 19 中的 JEP 428 和 JDK 20 中的 JEP 437。此次预览版本基于前两轮孵化的反馈进行了改进。

主要变化

当前提案的唯一显著变化是 StructuredTaskScope::fork(...) 方法现在返回一个 Subtask 对象,而不是 Future

目标

结构化并发旨在通过引入结构化并发的 API 来简化并发编程。它将运行在不同线程中的相关任务组视为一个单一的工作单元,从而简化错误处理和取消操作,提高可靠性,并增强可观察性。

示例代码

以下是一个使用 StructuredTaskScope 的示例代码:

Response handle() throws ExecutionException, InterruptedException {
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        Supplier<String>  user  = scope.fork(() -> findUser());
        Supplier<Integer> order = scope.fork(() -> fetchOrder());

        scope.join()            // 等待所有子任务完成
             .throwIfFailed();  // 传播错误

        // 所有子任务成功完成后,组合它们的结果
        return new Response(user.get(), order.get());
    }
    //...
}

启用预览功能

要使用 StructuredTaskScope API,开发者需要在编译和运行时启用预览功能:

javac --release 21 --enable-preview Main.java
java --enable-preview Main

或者使用源代码启动器:

java --source 21 --enable-preview Main.java

jshell 中使用时也需要启用预览功能:

jshell --enable-preview

子类

大多数情况下,开发者不会直接使用 StructuredTaskScope 类,而是使用其两个子类之一:

  • ShutdownOnFailure:当第一个子任务失败时关闭作用域。
  • ShutdownOnSuccess:当第一个子任务成功时关闭作用域。

设计理念

结构化并发模型提出,任务结构应反映代码结构。在单线程代码中,执行始终强制执行任务和子任务的层次结构,每个子任务的生存期由代码的语法块结构决定。

与现有并发模型对比

当前的并发编程模型(如 ExecutorService API)由于不受限制的并发模式引入了复杂性和风险。这些模型不强制执行或跟踪任务和子任务之间的关系,使得并发任务的管理和可观察性变得困难。

新 API 的优势

StructuredTaskScope 提供了比 ExecutorService 更简单、更安全的替代方案。该 API 封装了一组应一起完成的相关任务,任何子任务的失败都会导致剩余子任务的取消。

未来发展

该功能并不旨在替换 java.util.concurrent 包中的任何并发构造(如 ExecutorServiceFuture),也不旨在定义 Java 平台的最终结构化并发 API 或线程间共享数据流的方法。

开发者背景

该功能由 Oracle 的咨询技术成员 Ron Pressler 和 Java 平台组工程师 Alan Bateman 主导开发,旨在消除并发编程中的常见风险(如线程泄漏和取消延迟),并增强并发代码的可观察性。

进一步学习

开发者可以通过 InfoQ PodcastYouTube 视频和 Inside Java 文章深入了解结构化并发及其背景故事。

总结

JEP 453 为 JDK 21 引入了结构化并发 API,旨在简化并发编程,提高代码的可靠性和可观察性。该功能目前处于预览阶段,开发者可以通过启用预览功能来体验和使用。

阅读 108
0 条评论