Java jdk21- 453 Structured Concurrency结构化并发
一、结构化并发(Structured Concurrency)
结构化并发是Java 21引入的预览特性,它通过将并发任务组织成一个有明确生命周期和作用域的结构,使并发代码更易于理解、维护和调试。它解决了传统异步编程中的几个关键问题:任务泄漏、错误传播和上下文传递。
- 结构化任务作用域(StructuredTaskScope):定义并发任务的边界和生命周期
- 子任务:在作用域内启动的并发任务
- 作用域生命周期:作用域关闭时,所有子任务必须完成或被取消
- 错误传播:子任务的异常会传播到父作用域
“结构化并发”指的也是“父子结构”,即线程之间不是毫无关联,随意并发的,而是有清晰的父线程子线程抽象。线程 A 启动线程 B 后,A就是父线程,B就是子线程。结构化并发要求在父线程退出之前,所有子线程都要结束(成功完结或取消执行)

二、结构化并发与非结构化并发的技术实现对比
在Java中,结构化并发的实现主要依赖于新的API和语言特性,而非结构化并发则主要依赖传统的线程和线程池机制。
| 特性 | 结构化并发 | 非结构化并发 |
|---|---|---|
| 任务关系 | 父子结构明确 | 任务独立 |
| 生命周期管理 | 由框架统一管理 | 需手动管理 |
| 异常处理 | 统一捕获与传播 | 需单独处理 |
| 资源释放 | 自动释放 | 需手动释放 |
| 典型API | Java 21 StructuredTaskScope | ExecutorService、Thread |
二、结构化并发的核心组件
作用域(Scopes)
作用域是结构化并发的核心概念,用于管理一组任务的生命周期。通过 Scope 接口。
任务句柄(Task Handles)
任务句柄代表异步执行的任务
异常处理策略
结构化并发提供了多种异常处理模式:
-
ShutdownOnFailure:任何任务失败立即终止作用域。
-
ContinueOnFailure:允许任务继续执行,收集所有异常。
-
CustomExceptionHandler:自定义异常处理逻辑。
- 主作用域管理:使用StructuredTaskScope创建并发任务组,确保所有任务作为一个工作单元执行
- 任务启动机制:通过fork()方法启动异步任务,返回Subtask对象用于结果获取
- 异常处理策略:通过throwIfFailed()统一处理任务失败情况,保证错误传播
- 资源自动清理:采用try-with-resources语法,确保作用域正确关闭
- 任务状态监控:提供任务状态查询和异常获取功能
import java.util.concurrent.StructuredTaskScope;
public class StructuredConcurrency1 {
public static void main(String[] args) {
// 在主作用域中执行并发任务
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// 创建子作用域并启动异步任务
var task1 = scope.fork(() -> performTask("任务 1", 1000));
var task2 = scope.fork(() -> performTask("任务 2", 2000));
// 等待所有子任务完成
scope.join();
// 检查是否有任务失败
scope.throwIfFailed();
System.out.println("所有任务都已完成");
// 获取任务结果
System.out.println(task1.get()+" => "+task1.state());
System.out.println(task2.get()+" => "+task1.state());
} catch (Exception e) {
System.out.println("任务执行失败: " + e.getMessage());
}
}
private static String performTask(String taskName, int duration) {
try {
System.out.println(taskName + " 开始执行");
// 模拟任务执行时间
Thread.sleep(duration);
System.out.println(taskName + " 执行完成");
return taskName ;
} catch (InterruptedException e) {
// 恢复中断状态,以便上层调用者可以知道发生了中断
Thread.currentThread().interrupt();
throw new RuntimeException(taskName + " 被中断", e);
}
}
}

三、结构化并发的高级应用技巧
结构化并发:确保所有fork的任务都在scope作用域内管理
失败策略:采用
ShutdownOnFailure策略,任一任务失败即终止状态检查:通过
Subtask.State枚举检查任务执行状态模拟现实:订单数据有70%概率随机失败
import java.util.List;
import java.util.concurrent.StructuredTaskScope;
public class AdvancedStructuredConcurrency {
public static void main(String[] args) throws InterruptedException {
// 使用失败处理策略
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// 启动多个并发任务
List<StructuredTaskScope.Subtask<String>> tasks = List.of(
scope.fork(() -> fetchData("用户数据", 1000)),
scope.fork(() -> fetchData("订单数据", 900)),
scope.fork(() -> fetchData("库存数据", 1500))
);
// 等待所有任务完成
scope.join();
// 处理任务结果
for (var task : tasks) {
if (task.state() == StructuredTaskScope.Subtask.State.SUCCESS) {
System.out.println("成功获取: " + task.get());
} else if (task.state() == StructuredTaskScope.Subtask.State.FAILED) {
System.out.println("任务失败: " + task.exception().getMessage());
}
}
}
}
private static String fetchData(String dataType, int timeout) {
try {
// 模拟数据获取
Thread.sleep(timeout);
double random = Math.random();
System.out.println(random);
if (dataType.contains("订单") && random > 0.7) {
throw new RuntimeException(dataType + " 获取失败");
}
return dataType + " - 耗时 " + timeout + "ms";
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(dataType + " 获取被中断");
}
}
}
成功如图:

失败如图:
![]()
总之,结构化并发需要 JDK 21 及以上版本支持,但它已经展现出巨大的潜力。随着 Java 生态的持续优化,结构化并发将成为现代 Java 开发的标准实践。合理使用结构化并发,能够有效减少并发编程中的错误,提高系统的可靠性和性能。
更多推荐

所有评论(0)