Ver código fonte

docs:blog 补 orTimeout/completeOnTimeout/exceptionallyCompose 速查行与超时最佳实践

yangyi 1 semana atrás
pai
commit
ccf21db3d5
1 arquivos alterados com 8 adições e 2 exclusões
  1. 8 2
      completablefuture-blog.md

+ 8 - 2
completablefuture-blog.md

@@ -27,21 +27,27 @@
 | 全部完成 | `allOf(...)` | — | `CF<Void>`(各自再 join 汇总) |
 | 任一完成 | `anyOf(...)` | — | `CF<Object>`(需转类型) |
 | 失败降级 | `exceptionally` | `Function` | `CF<T>` |
+| 异常后异步续接(展平) | `exceptionallyCompose` | `Function→CF` | `CF<T>` |
 | 成败都观察 | `whenComplete` | `BiConsumer` | 不改结果 |
 | 成败都能处理 | `handle` | `BiFunction` | `CF<U>` |
+| 限时等待,超时快速失败 | `orTimeout(超时, 单位)` | — | `CF<T>` |
+| 超时补默认值 | `completeOnTimeout(v, 超时, 单位)` | — | `CF<T>` |
+| 带超时取结果 | `get(超时, 单位)` | — | `T` |
+| 是否已结束 | `isDone` | — | `boolean` |
 | 手动定结果 | `complete` / `completeExceptionally` | — | `boolean` |
-| 强制覆盖 | `obtrudeValue` | — | `void`(慎用) |
+| 强制覆盖/强制异常 | `obtrudeValue` / `obtrudeException` | — | `void`(慎用) |
 | 取消 | `cancel(true)` | — | `boolean` |
 
 记忆口诀:**Apply=加工出结果,Accept=消费不出结果,Run=不管结果只管流程**;后缀 Both=Either 只差"都要"还是"谁先"。
 
-## 条最佳实践
+## 条最佳实践
 
 1. **I/O 一定配独立线程池。** 默认 `ForkJoinPool.commonPool()` 线程数是 `CPU核数-1`,回调里再嵌 `supplyAsync` 就会互相等(Thread Starvation),直接把池子卡死。给耗时调用 `new ThreadPoolExecutor(...)` 并传进 Async 方法。
 2. **组装 BFF / RPC 并发调用用 `allOf`。** 一次性把下游都发出去真并行,别用 `for + get()` 退化成串行。注意 `allOf` 返回 `Void`,汇总前再逐个 `join()`。
 3. **回调里禁止 `join()/get()`。** 它阻塞的是当前执行线程;在一个 worker 上阻塞等另一个 worker,就是 2 号事故的引信。
 4. **统一异常出口。** 想兜底恢复用 `exceptionally`/`handle`,只想记录日志用 `whenComplete`(它不会吞异常,异常仍会沿链传播,最终 `join()` 抛 `CompletionException`,要用 `getCause()` 取原始异常)。
 5. **链式只加一次终端操作。** `future.thenApply(...).thenApply(...)` 是合法的,"上了链就别回头",避免把同一个 Future 反复 `join()` 造成多次阻塞。
+6. **对外异步调用一律配超时。** `orTimeout(2, SECONDS)` 让调用方快速失败(注意它**不会取消底层任务**,只是放弃等待);"过期给默认值也能接受"的场景用 `completeOnTimeout(v, 2, SECONDS)` 更省心。没有超时的异步外呼,等于给自己埋一颗"线程挂死"的雷。
 
 ## 三个高频坑