thenRun 是 CompletableFuture 中用于任务成功完成后执行无参无返回动作的回调方法,接收 Runnable,不依赖前序结果、不产生新结果,适用于日志记录等收尾工作,异常时不执行,且默认在前序任务完成的同一线程中运行。

thenRun 是 CompletableFuture 提供的一个回调方法,用于在前一个异步任务**成功完成**后,**不依赖其结果、也不返回新结果**地执行一个无参的后续动作。
核心特点:无输入、无输出、只做事情
它接收一个 Runnable,也就是一个没有参数、没有返回值的函数式接口。这意味着:
- 你无法拿到上一个任务的计算结果(比如不能用
result.toString()) - 它本身也不会产生新的
CompletableFuture结果(不支持链式返回值处理) - 适合做“收尾工作”:如记录日志、发通知、清理资源、更新 UI 状态等
基本用法示例
假设你有一个异步查询用户信息的任务:
```javaCompletableFuture<String> userFuture = CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作
try { Thread.sleep(1000); } catch (InterruptedException e) {}
return "Alice";
});
// thenRun 在 userFuture 完成后执行,但拿不到 "Alice"
userFuture.thenRun(() -> {
System.out.println("用户信息已加载完毕"); // ✅ 可以执行
// System.out.println(result); ❌ result 不可见
});
```
和 thenAccept / thenApply 的关键区别
三者都用于后续处理,但职责不同:
立即学习“Java免费学习笔记(深入)”;
- thenRun:只执行动作,不关心结果,不产出新结果
-
thenAccept:能接收上一步的结果(
Consumer<T>),但不返回新值 -
thenApply:能接收结果并返回新值(
Function<T,R>),形成新的CompletableFuture<R>
如果你需要打印用户名,应该用 thenAccept;如果只是打个日志说“完成了”,thenRun 更简洁准确。
注意执行线程与异常情况
thenRun 默认在前一个任务完成的**同一线程**中执行(即由哪个线程结束前序任务,就由谁执行 thenRun)。若希望指定线程池,要用 thenRunAsync(Runnable, Executor):
ExecutorService pool = Executors.newFixedThreadPool(3);
userFuture.thenRunAsync(() -> {
System.out.println("在自定义线程池中执行收尾");
}, pool);
```
另外,如果前一个任务抛出异常,thenRun **不会执行**——它只响应正常完成(complete),不处理异常(异常需用 exceptionally 或 handle 捕获)。


















