直接回答:传统并发任务管理是“散装”的:ExecutorService 提交出去的子任务与父任务没有结构关系——父任务结束了子任务还在跑(线程泄漏)、子任务失败了父任务拿到不完整结果(错误被吞)、thread dump 里看不出任务的归属树。结构化并发把任务树变成语法结构:StructuredTaskScope 内 fork 的子任务生命周期被 scope 边界框死,离开 scope 必然要么全部完成要么全部取消,父子关系在观测工具中清晰可见。
展开解析:两种内置策略对应两类业务语义:ShutdownOnFailure——任一子任务失败即取消其余,适合“聚合多个数据源,缺一个就整体失败”的页面组装;ShutdownOnSuccess——拿到第一个成功结果就取消其余,适合“多副本查询取最快”的冗余调用。与 CompletableFuture 对比:CF 的组合 API(allOf/anyOf)能表达同样逻辑但取消传播要手工接线,超时与取消的语义散落在各处,结构化并发把它们收进 scope 一处。与虚拟线程是绝配:fork 出来的子任务就是虚拟线程,一任务一线程无池化心智负担。落地注意:scope 内 fork 的子任务抛出的异常由 join 时统一处理(Joiner 定制汇总策略);取消是协作式的,子任务里的阻塞调用要响应中断;JDK 21~22 是预览、23 转正 API 有调整(Joiner 抽象),生产引用前核对版本。价值定位:它不改变性能,改变的是并发代码的可维护性与可靠性下限。
追问方向:Joiner 能定制哪些汇总语义?与 Reactor/RxJava 的边界在哪?
(约 470 字)