# Java 异步任务

# 力量：$E=mc^2$
这里需要先说明一下：在标准的 Java `CompletableFuture` API 中， **`thenApplyAsync`**。

下面我来详细解释 `thenApply`、`thenAccept` 和 `thenApplyAsync` 的区别。

### 1. `thenApply` vs `thenAccept`：对结果的处理方式不同

它们都是在前一个异步任务完成后执行的回调，核心区别在于**对任务结果的处理和返回**。

| 方法 | 函数式接口 | 入参 | 返回值 | 用途 |
| :--- | :--- | :--- | :--- | :--- |
| **`thenApply`** | `Function<T, R>` | 有（上一个任务的结果） | **有**（处理后的新结果） | **转换**结果，例如将字符串转换为它的长度。 |
| **`thenAccept`** | `Consumer<T>` | 有（上一个任务的结果） | **无** (`CompletableFuture<Void>`) | **消费**结果，执行一个动作但不产生新值，例如打印结果。 |

**代码示例对比：**

```java
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");

// thenApply：有入参，有返回值，用于转换
CompletableFuture<Integer> applyFuture = future.thenApply(s -> s.length()); 
// applyFuture 的结果是 Integer 类型的 5

// thenAccept：有入参，无返回值，用于消费
CompletableFuture<Void> acceptFuture = future.thenAccept(s -> System.out.println(s)); 
// acceptFuture 没有结果，只是打印 "Hello"
```

还有一个 `thenRun`，它不接收上一个任务的结果，也不返回任何值，只用于在任务完成后执行一个动作。

### 2. `thenApply` vs `thenApplyAsync`：执行线程不同

`thenApply` 和 `thenApplyAsync` 功能完全相同，都是转换上一个任务的结果。唯一的区别在于**执行回调任务的线程**。

*   **`thenApply` (同步执行)**：回调任务通常由**同一个线程**执行，这个线程可能是上一个任务的线程，也可能是调用 `thenApply` 的线程（如 `main` 线程）。可以理解为，它能保证执行顺序，但可能会阻塞当前线程。
*   **`thenApplyAsync` (异步执行)**：回调任务会被提交到 **`ForkJoinPool.commonPool()`** 线程池中，由**新的线程**来执行。这样能保证回调任务不会阻塞当前线程，实现了真正的异步。

**同理，`thenAccept` 也有对应的异步版本 `thenAcceptAsync`**。

### 总结

*   如果你的**重点**是**转换数据**，需要返回一个新结果，用 `thenApply`（或其异步版本 `thenApplyAsync`）。
*   如果你的**重点**是**执行一个动作**（如打印、日志），不需要返回结果，用 `thenAccept`（或其异步版本 `thenAcceptAsync`）。
*   你需要根据对**执行线程**的控制需求，来选择同步版本还是异步版本。