📚 Java 21 结构化并发漫画手册

程序猿:并发编程头都大了!线程泄漏、异常乱飞、任务取消难管理,天天写Bug😫
Java精灵:试试结构化并发呀!把所有任务关进「作用域笼子」,生命周期统一管,出错一起扛,资源绝不漏~

场景一:微服务扇出调用 | 多路接口并行查

🎬 小剧场:订单服务要查详情,得同时喊用户、商品、物流三个接口。以前一个挂了其他还在傻跑,现在结构化并发当总管,一个失败全叫停!

🏪 业务场景:电商订单详情聚合、多接口数据聚合、并行查询第三方服务

// 订单详情聚合:并行查询3个接口 try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { // 分叉3个子任务 Subtask<User> userTask = scope.fork(() -> userApi.getUser(userId)); Subtask<Product> prodTask = scope.fork(() -> productApi.getProduct(prodId)); Subtask<Logistics> logiTask = scope.fork(() -> logisticsApi.getLogistics(orderId)); // 等待所有任务完成,失败则抛出异常 scope.join().throwIfFailed(); // 聚合结果 return new OrderDetail( userTask.get(), prodTask.get(), logiTask.get() ); }

场景二:批量任务超时管控 | 到点全下班

🎬 小剧场:产品经理说这批任务必须5秒内出结果!以前超时了线程还在后台偷偷跑,现在结构化并发到点直接全员取消,绝不拖泥带水~

📊 业务场景:报表生成、批量数据计算、限时查询任务、超时降级场景

// 批量任务设置5秒全局超时 try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { List<Subtask<ReportItem>> tasks = dataIds.stream() .map(id -> scope.fork(() -> calcReportItem(id))) .toList(); // 最多等5秒,超时直接取消所有任务 scope.joinUntil(Instant.now().plusSeconds(5)); scope.throwIfFailed(); return tasks.stream() .map(Subtask::get) .toList(); }

场景三:分治计算任务 | 大任务拆小齐心算

🎬 小剧场:超大数组求和算不完?拆成N份,每个小任务算一段,最后拼起来!结构化并发管着所有小任务,层级清晰不混乱~

🔢 业务场景:大文件统计、数组并行计算、日志分析、数据分块处理

// 分治求和:大数组拆成小数组并行计算 long parallelSum(long[] arr, int left, int right) { if (right - left <= 1000) { return Arrays.stream(arr, left, right).sum(); } int mid = (left + right) / 2; try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { var leftTask = scope.fork(() -> parallelSum(arr, left, mid)); var rightTask = scope.fork(() -> parallelSum(arr, mid, right)); scope.join().throwIfFailed(); return leftTask.get() + rightTask.get(); } }

场景四:嵌套任务编排 | 任务套娃不乱套

🎬 小剧场:主任务下面有A、B两组,A组又分A1、A2两个小任务!嵌套作用域安排上,每层管自己的娃,各层互不干扰~

🏗️ 业务场景:复杂业务流程编排、商品上架、多级数据处理、有层级依赖的并发任务

// 商品上架:嵌套作用域管理多级任务 try (var mainScope = new StructuredTaskScope.ShutdownOnFailure()) { // 一级任务:基础信息组 + 素材处理组 var baseTask = mainScope.fork(() -> getBaseInfo(productId)); var assetTask = mainScope.fork(() -> { // 二级嵌套作用域:并行处理图片和描述 try (var assetScope = new StructuredTaskScope.ShutdownOnFailure()) { var imgTask = assetScope.fork(() -> processImages(productId)); var descTask = assetScope.fork(() -> generateDesc(productId)); assetScope.join().throwIfFailed(); return new AssetResult(imgTask.get(), descTask.get()); } }); mainScope.join().throwIfFailed(); return buildProduct(baseTask.get(), assetTask.get()); }

场景五:事务型并发操作 | 要成一起成,要败一起败

🎬 小剧场:这几个数据库操作必须同时成功!不然全回滚!结构化并发开启「一败全败」模式,一个挂了全叫停,完美配合事务回滚~

💳 业务场景:多数据源写入、分布式事务、批量支付、原子性并发操作

// 批量订单入账:全部成功才提交,失败全回滚 try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { List<Subtask<Boolean>> tasks = orders.stream() .map(order -> scope.fork(() -> accountService.credit(order))) .toList(); scope.join().throwIfFailed(); // 任意失败直接抛异常 transaction.commit(); // 全部成功才提交事务 } catch (Exception e) { transaction.rollback(); // 异常统一回滚 throw e; }

场景六:多源竞速查询 | 谁快用谁的

🎬 小剧场:查数据同时喊缓存和数据库,谁先回来就用谁的!以前得自己等最快的,现在 ShutdownOnSuccess 模式,第一个成功直接全员下班~

⚡ 业务场景:多级缓存查询、冗余服务调用、接口容灾竞速、最快结果获取

// 缓存+数据库+备份接口竞速查询,取最快返回的结果 try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) { scope.fork(() -> redisCache.get(key)); scope.fork(() -> mysqlDb.query(key)); scope.fork(() -> backupApi.query(key)); // 等待第一个成功的结果,其他任务自动取消 return scope.join().result(); }
Java精灵:结构化并发让并发编程回归「结构化」,生命周期可控、错误处理清晰、资源零泄漏~
💡 小提示:Java 21 中结构化并发处于预览阶段,使用时需添加 JVM 参数 --enable-preview 哦~