bigywater.tech
Java · 156

CompletableFuture 超时与取消:任务到底能不能停

给 CompletableFuture 设了超时、调了 cancel,底层任务到底停没停?这篇用会计数的任务逐一验证(默认线程池的行为见后面的 CompletableFuture 默认执行器一篇)。

4 → 15 步
orTimeout 超时后底层任务仍在继续执行
false
CompletableFuture.cancel(true) 之后任务被中断了吗
3 步
executor.submit 的 Future.cancel(true) 之后任务停在的步数

orTimeout

实测 · 本机执行输出
  300 ms 后 join() 抛 TimeoutException;f.isCompletedExceptionally = true
  超时时任务已执行 4 步;再过 1.2 秒已执行 15 步,任务被中断过吗:false(任务还在后台继续跑)

cancel(true)

实测 · 本机执行输出
  cancel(true) 返回 true,isCancelled = true,isDone = true
  join() 抛 CancellationException
  依赖它的 thenApply 阶段 join() 抛 CompletionException,cause = CancellationException
  取消时任务已执行 3 步;再过 1.2 秒已执行 15 步,任务被中断过吗:false(cancel(true) 的参数对 CompletableFuture 没有效果)

能中断任务的做法

实测 · 本机执行输出
  executor.submit 的 Future:cancel(true) 返回 true,任务被中断了吗:true;取消后 300 ms 时 3 步,再过 1 秒 3 步(不再增长)
  组合写法:CompletableFuture 超时(TimeoutException)后,在 whenComplete 里对底层 Future 调 cancel(true)
  底层任务被中断了吗:true;超时后 0.3 秒 3 步,再过 0.8 秒 3 步(不再增长)

completeOnTimeout 与 get

实测 · 本机执行输出
  completeOnTimeout:default(超时用默认值完成,没有异常)
  get(100ms) 抛 TimeoutException;之后 g.isDone = false(get 的超时只是不等了,future 本身没有被完成)
  之后再 join() 得到:real

分步演示

CompletableFuture 超时与取消
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12
    • 没有验证:JDK 17 与 27 上是否相同、任务不响应中断(忙等)时 cancel(true) 的效果、ForkJoinPool 公共池的线程回收、Java 的结构化并发(StructuredTaskScope)如何改变这件事(后面的篇目);步数是一次运行的结果
    京ICP备2026067502号-1京公网安备11010502063487号