thenrun适用于前序异步任务正常完成后执行无参无返回值的副作用操作。它接收runnable,仅在成功完成时触发,不处理异常、不依赖结果、不改变数据流;需异常后也执行应选whencomplete。

thenRun 是 CompletableFuture 提供的“无参无返回值”回调方法,适用于前序异步任务完成(无论成功或失败)后,**只执行副作用操作、不依赖结果、也不需要返回新 Future** 的场景。
什么时候该用 thenRun?
当你只需要在上一个异步任务结束后“做点事”,比如:记录日志、发通知、清理资源、更新 UI 状态,且这些动作:
- 不需要前一个任务的返回值
- 不改变后续链式调用的数据流(即不返回新值)
- 不关心前一个任务是成功还是异常结束(⚠️注意:默认情况下
thenRun只在正常完成时触发;若需异常后也执行,得用whenComplete或handle)
基本写法和线程行为
thenRun 接收一个 Runnable,它会在前一个 CompletableFuture 正常完成(即未抛出异常)后执行。执行线程取决于前序任务的完成方式:
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
- 如果前序任务是同步完成(如
completedFuture),thenRun默认在当前线程执行 - 如果前序任务是异步完成(如
supplyAsync),thenRun通常在同一个线程池中执行(除非显式用thenRunAsync指定其他线程池)
示例:
CompletableFutureThread.sleep(1000);
return "done";
});
future.thenRun(() -> System.out.println("任务已完成,无需结果")); // 输出在 ForkJoinPool 线程中
thenRun vs thenRunAsync:关键区别
两者都接受 Runnable,但调度策略不同:
-
thenRun(Runnable):可能在前序任务完成的**同一线程**执行(非强制异步) -
thenRunAsync(Runnable):**强制提交到线程池**(默认ForkJoinPool.commonPool(),可传第二个参数指定自定义 Executor)
推荐在涉及 I/O、耗时操作或需解耦线程时优先用 thenRunAsync,避免阻塞前序任务的线程。
常见误区提醒
-
thenRun不会接收上一个 stage 的结果 —— 想用结果请改用thenAccept -
thenRun不处理异常 —— 若前序任务抛异常,它不会执行;需要兜底逻辑请用whenComplete((v, t) -> {...}) - 不要在
thenRun中 return 值或试图返回新 Future —— 它签名是CompletableFuture<void></void>,链式调用只能接其他thenXxx或终止
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










