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 请求或回滚远端操作。并行是否更快也取决于任务依赖、线程池容量和阻塞比例,而不是换一种返回类型就自然成立。