completablefuture.ortimeout 不会中断任务,仅超时后以 timeoutexception 完成;completeontimeout 则用默认值完成且允许原结果覆盖。二者均不调用 cancel() 或中断线程,java 9+ 引入,java 8 需借助延迟执行器或第三方库模拟。

CompletableFuture.orTimeout 会中断任务吗?
不会。调用 orTimeout 只是给整个 CompletableFuture 加一个“超时截止时间”,到期后若仍未完成,就以 TimeoutException 异常完成该 future;它**不调用底层任务的 cancel(),也不中断线程**。
这意味着:如果原始任务是 CPU 密集型或阻塞 I/O(比如没设 socket timeout 的 HttpURLConnection),它仍会在后台继续跑,只是你不再等它了。
- 适用场景:你只关心“结果是否在 X 秒内回来”,不关心任务本身是否停掉
- 常见错误:以为加了
orTimeout(3, TimeUnit.SECONDS)就能防止慢查询拖垮服务——其实线程池里那个任务还在跑,可能持续占用连接、锁或内存 - 替代思路:真要中断,得配合可取消的任务(如
ExecutorService.submit(Callable)返回的Future),再用completeOnTimeout或手动处理
completeOnTimeout 和 orTimeout 的关键区别
二者都设超时,但语义和行为完全不同:
-
orTimeout:超时 → 以TimeoutException完成;之后再有人调用complete()或任务自己结束,都会失败(抛IllegalStateException) -
completeOnTimeout:超时 → 用你指定的默认值完成;但如果原任务后来成功返回了,它的结果会**覆盖**默认值(前提是还没被消费)
简单说:orTimeout 是“超时即失败”,completeOnTimeout 是“超时先给个兜底值,有更好结果就换”。
立即学习“Java免费学习笔记(深入)”;
示例:
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(5000); } catch (InterruptedException e) {}
return "done";
}).completeOnTimeout("fallback", 1, TimeUnit.SECONDS);
1 秒后返回 "fallback",但 5 秒后若原任务完成,cf.get() 会拿到 "done"(除非已被取走)。
Java 9+ 才有,但低版本怎么模拟?
Java 8 没有这两个方法,直接升级 JDK 是最稳的;如果卡在 8,别手写定时器轮询,容易漏异常、线程泄漏。
推荐方案:
- 用
CompletableFuture.delayedExecutor+orTimeout的语义模拟:启动一个延迟任务,在超时点尝试completeExceptionally(new TimeoutException()),但要注意竞态——原任务可能刚好完成,此时completeExceptionally失败,属于正常 - 更稳妥的是引入
net.jodah:failsafe或io.vavr:Vavr,它们对超时封装更健壮,且明确区分“中断任务”和“放弃等待” - 别用
Thread.sleep+isDone轮询:性能差,且无法响应中断
超时单位传错或传 0 会怎样?
传 0 或负数,orTimeout 和 completeOnTimeout 都会立即触发超时逻辑:
-
orTimeout(0, TimeUnit.NANOSECONDS)→ 立即以TimeoutException完成 -
completeOnTimeout("x", 0, TimeUnit.SECONDS)→ 立即用"x"完成
这在测试中可以快速验证 fallback 路径,但线上千万别硬编码 0——尤其当单位是 TimeUnit.DAYS 时,orTimeout(0, TimeUnit.DAYS) 看着像“不限时”,实则秒超时。
容易被忽略的一点:这两个方法内部用的是 System.nanoTime() 计时,不是系统时钟,所以不怕 NTP 调整导致误超时;但如果你在 mock 时间(比如用 java.time.Clock),它不影响这里——因为底层不走 Clock。










