什么是CompletableFuture?
提到CompletableFuture就需要先提到Future,Future就是Java里的一个接口,代表异步计算返回的结果,获取方式就是通过线程池提交Callable或Runnable任务返回,但是呢调用get()会阻塞当前线程,知道任务完成
获取结果:通过 get() 方法获取任务执行结果。如果任务还没完成,调用 get() 会阻塞当前线程,直到任务完成。你也可以使用带超时参数的 get(long timeout, TimeUnit unit) 方法,避免长时间阻塞。
取消任务:使用 cancel(boolean mayInterruptIfRunning) 方法尝试取消任务。
检查状态:isDone() 方法判断任务是否已完成(包括正常结束、异常或取消),isCancelled() 方法则判断任务是否已被取消
Future使用代码示例:
public class FutureExample {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(2);
// 提交Callable任务,返回Future
Future<String> future = executor.submit(() -> {
Thread.sleep(2000);
return "Hello from Future!";
});
System.out.println("Do something else while task is running...");
// get()会阻塞,直到任务完成并返回结果
String result = future.get();
System.out.println(result);
executor.shutdown();
}
}
Java8就引入了CompletableFuture,一个强大的异步编程工具。允许非阻塞地处理异步任务,并且可以通过链式调用组合多个异步操作,CompletableFuture是Future的升级版,Future能做的它都能做
CompletableFuture 的核心优势在于它实现了 CompletionStage 接口,这让它拥有了链式调用和任务组合的能力。
为了方便理解,这里举个例子:
回调:
我们想要去一家餐厅吃饭,餐厅通常会取号然后让你等待,当菜做好了就会通知你,在这个等待的过程中你可以做自己的事,这叫做异步
Future.get()就好像是餐厅叫到你号时,你去取餐的那个动作,这时候餐还没做好(任务未完成),就会原地等待(线程阻塞),直到餐做好了,你才能够去拿到餐,这个过程你只能返回询问是否做好(isDone())或干脆阻塞等待。
CompletableFuture允许你预定回调函数(thenAccept),出结果后则通知你

示例代码:
public class CompletableFutureRestaurantExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 模拟一个餐厅的后厨线程池
// 实际开发中,建议根据业务需求使用自定义线程池,而非默认的ForkJoinPool.commonPool()
// 厨师开始烹饪主菜(异步任务,有返回值)
CompletableFuture<String> mainDishFuture = CompletableFuture.supplyAsync(() -> {
try {
System.out.println("【厨师】开始烹饪主菜:红烧狮子头...(线程: " + Thread.currentThread().getName() + ")");
Thread.sleep(3000); // 模拟烹饪耗时
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "红烧狮子头";
});
// 同时准备凉菜(另一个异步任务,有返回值)
CompletableFuture<String> coldDishFuture = CompletableFuture.supplyAsync(() -> {
try {
System.out.println("【厨师】开始准备凉菜:凉拌黄瓜...(线程: " + Thread.currentThread().getName() + ")");
Thread.sleep(1500); // 模拟准备耗时
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "凉拌黄瓜";
});
// 异步组合任务:等主菜和凉菜都做好后,开始准备套餐
CompletableFuture<String> mealFuture = mainDishFuture
.thenCombineAsync(coldDishFuture, (mainDish, coldDish) -> {
System.out.println("【厨师】开始组合套餐: " + mainDish + " + " + coldDish + "(线程: " + Thread.currentThread().getName() + ")");
return "套餐: " + mainDish + " + " + coldDish;
});
// 定义异常处理:如果任何一道菜制作失败,提供默认菜品
CompletableFuture<String> exceptionHandledFuture = mealFuture.exceptionally(ex -> {
System.err.println("【后厨】制作过程中出现异常,提供默认套餐: " + ex.getMessage());
return "默认套餐(炒饭+酸辣汤)";
});
// 最终消费结果:通知顾客取餐
exceptionHandledFuture.thenAccept(meal -> {
System.out.println("【服务员】餐已准备好: " + meal + ",请顾客取餐!(线程: " + Thread.currentThread().getName() + ")");
});
// 主线程(模拟顾客等待)
System.out.println("【顾客】已下单,在座位上玩手机...(线程: " + Thread.currentThread().getName() + ")");
// 为了演示,主线程等待所有异步任务完成(实际生产中可能不会这样)
exceptionHandledFuture.get(); // 或者使用 join()
System.out.println("【顾客】收到通知,前往取餐。");
}
}
任务组合:
Future很难处理多个异步任务的依赖关系,CompletableFuture提供了ompletableFuture 提供了 thenCombine(等两个任务都完成再处理)、thenCompose(第一个任务的结果作为第二个任务的输入)、allOf(等所有任务完成)、anyOf(等任意一个任务完成) 等方法,轻松编排复杂异步流程
异常处理:
Future的异常需在get()时使用try-catch捕获ExcutionException,而CompletableFuture提供了exceptionally、handle等方法,可以处理链式中任何阶段的异常
手动完成:Future 不能手动设置结果。CompletableFuture 可以通过 complete()、completeExceptionally() 手动设置结果或异常
总结:
CompletableFuture在Future的基础上,提供了更强大的异步任务编排和处理能力,不需要阻塞主线程,同时处理多个任务,让异步编程更流畅
更多推荐

所有评论(0)