Future 描述“将来可取得的计算结果”,CompletableFuture 在此基础上增加了“完成后继续做什么”的阶段组合能力。两者不是两个平级接口:CompletableFuture 是同时实现 Future 和 CompletionStage 的类。Java 8 CompletableFuture

Future:由调用者取得结果

ExecutorService.submit 返回 Future。调用者可以查询是否完成、请求取消,或通过 get 等待结果:

Future<Integer> result = pool.submit(() -> 42);
Integer value = result.get();

pool 是已有的 ExecutorService。get 可能阻塞;带超时的 get 可以限制调用者等待多久,但等待超时不代表任务已经停止。任务失败时,要查看 ExecutionException 的 cause;等待被中断时,不应吞掉取消信号。

CompletableFuture:把依赖步骤写进链路

以下 Java 8 示例显式传入线程池,并在消费结果后关闭它:

import java.util.concurrent.*;

public class FutureStagesDemo {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        try {
            CompletableFuture<String> text = CompletableFuture
                .supplyAsync(() -> 42, pool)
                .thenApply(value -> "结果是:" + value);

            System.out.println(text.get(2, TimeUnit.SECONDS));
        } catch (ExecutionException error) {
            System.err.println("计算失败:" + error.getCause());
        } catch (TimeoutException error) {
            System.err.println("等待超时,任务未必停止");
        } catch (InterruptedException error) {
            Thread.currentThread().interrupt();
        } finally {
            pool.shutdown();
        }
    }
}

这个例子说明阶段关系,不用于比较吞吐量。shutdown 不会强行终止已提交任务;真实服务还需设计容量、超时、取消及完整关闭策略。

thenApply、thenCompose 与 Async

thenApply 把一个值转换为另一个值。如果下一步已经返回 CompletionStage,使用 thenCompose 可以把两层阶段展平:

CompletableFuture<Integer> answer = CompletableFuture
    .completedFuture(21)
    .thenCompose(value -> CompletableFuture.completedFuture(value * 2));

非 Async 方法不保证新建线程,可能由完成前一步的线程或调用者执行。带 Async 的方法应明确执行器;没有显式 Executor 的 Java 8 异步方法通常使用 commonPool,不能默认认为它们使用业务线程池。

失败与取消也是链路的一部分

exceptionally 可以把失败转换为备用值,handle 可同时观察正常与异常结果,whenComplete 适合观察完成状态。是否把错误转换为正常结果,必须符合业务含义,不能为了不报错而无条件返回成功默认值。

CompletableFuture.cancel 主要改变结果的完成状态,不等于中断实际计算、撤销 HTTP 请求或回滚远端操作。并行是否更快也取决于任务依赖、线程池容量和阻塞比例,而不是换一种返回类型就自然成立。