CompletableFuture 详解

什么是CompletableFuture

CompletableFuture 是 Java 8 中新增的一个异步编程工具类,它是基于 Future 和 CompletionStage 接口构建的,它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。

主要用于异步执行任务并返回结果,实现异步计算和操作组合。它提供了一种灵活、可组合的方式来实现异步计算,同时也提供了异常处理、取消、超时等特性。在CompletableFuture中,我们可以通过回调函数来处理任务的结果,也可以使用其它方法来组合多个CompletableFuture对象,以构建更复杂的异步操作流水线。
Future 可以使用 Runnable 或 Callable 实例来完成提交的任务,CompletableFuture解决了Future存在如下几个问题:
1.阻塞: 调用 get() 方法会一直阻塞,直到等待直到计算完成,它没有提供任何方法可以在完成时通知,同时也不具有附加回调函数的功能。
2. 链式调用和结果聚合处理: 在很多时候我们想链接多个 Future 来完成耗时较长的计算,此时需要 合并结果并将结果发送到另一个任务中,该接口很难完成这种处理。
3.异常处理: Future 没有提供任何异常处理的方式。

自身特性

异步执行:CompletableFuture 可以在新的线程上异步执行计算或操作,从而不会阻塞主线程,提高程序的响应速度。

可组合性:CompletableFuture 的操作可以组合成一个或多个的 CompletableFuture 对象,从而构成复杂的异步计算链。

异常处理:CompletableFuture 可以对异常进行处理,通过 exceptionally() 方法可以捕获计算中的异常并返回默认值。

取消与超时:CompletableFuture 支持取消异步任务,还可以设置超时时间来避免任务的无限等待。

非阻塞式等待:CompletableFuture 提供了非阻塞式的等待方法,如 join() 和 getNow() 方法。

如何使用

1、异步执行一个任务并获取结果
通过 CompletableFuture 的静态方法 supplyAsync() 可以异步执行一个任务,返回 CompletableFuture 对象,通过该对象可以获取任务执行的结果。

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    return "Hello CompletableFuture";
});
String result = future.get(); // 阻塞等待任务执行完成并获取结果
System.out.println(result);

2.异步执行一个任务并处理异常
CompletableFuture 提供了方法 handle() 来处理异步任务执行过程中的异常,它可以处理任务完成时的异常,也可以处理任务执行过程中的异常。

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 执行一些可能会出现异常的操作
    throw new RuntimeException("Something went wrong");
}).handle((result, exception) -> {
    if (exception != null) {
        System.out.println("Task failed with exception: " + exception);
        return "default value";
    } else {
        return result;
    }
});
String result = future.get();
System.out.println(result);

3.异步执行多个任务并合并结果
通过 CompletableFuture 的静态方法 allOf() 可以并行执行多个任务,等待所有任务完成后,通过 CompletableFuture.join() 方法合并所有任务的结果。

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "CompletableFuture");
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "Java");
 
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(future1, future2, future3);
combinedFuture.get();
 
String result = Stream.of(future1, future2, future3)
        .map(CompletableFuture::join)
        .collect(Collectors.joining(" "));
System.out.println(result);

4.异步执行多个任务并处理其中一个任务的结果
通过 CompletableFuture 的静态方法 anyOf() 可以并行执行多个任务,只要有一个任务完成,就会立即返回其结果。

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "Result 1";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result 2");
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "Result 3");
 
CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2, future3);
 
Object result = anyOfFuture.get();
System.out.println(result);

5、串行执行多个任务
通过 CompletableFuture 的方法 thenApply()、thenAccept() 和 thenRun() 可以串行执行多个任务,每个任务在前一个任务完成后才会执行。

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = future1.thenApply(result -> result + " CompletableFuture");
CompletableFuture<Void> future3 = future2.thenAccept(result -> System

6、 检查异步任务是否执行完成和执行回调
在CompletableFuture中,可以使用isDone()方法来检查异步任务是否已经执行完毕。该方法会返回一个boolean类型的值,表示异步任务是否已经完成。如果异步任务已经完成,则可以通过调用get()方法获取其返回值;如果异步任务还没有完成,则可以通过注册回调函数来等待其完成。

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 异步任务
    return "Hello, World!";
});
 
// 检查异步任务是否已经完成
if (future.isDone()) {
    // 获取异步任务的返回值
    String result = future.get();
    System.out.println(result);
} else {
    // 注册回调函数,在异步任务完成时获取其返回值
    future.thenAccept(result -> {
        System.out.println(result);
    });
}

用法总结

一、实例化创建

// 返回一个新的CompletableFuture,由线程池ForkJoinPool.commonPool()中运行的任务异步完成,不会返回结果。
public static CompletableFuture<Void> runAsync(Runnable runnable);
// 返回一个新的CompletableFuture,运行任务时可以指定自定义线程池来实现异步,不会返回结果。
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor);

// 返回由线程池ForkJoinPool.commonPool()中运行的任务异步完成的新CompletableFuture,可以返回异步线程执行之后的结果。
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor);

二、两种方式实现异步
supply 开头:该方法可以返回异步线程执行之后的结果;
run 开头:该方法不会返回结果,就只是执行线程任务。

三、返回结果的方式:
get():阻塞式获取执行结果,如果任务还没有完成则会阻塞等待知直到任务执行完成
get(long timeout, TimeUnit unit):带超时的阻塞式获取执行结果
getNow():如果已完成,立刻返回执行结果,否则返回给定的valueIfAbsent
join():该方法和get()方法作用一样, 不抛异常的阻塞式获取异步执行结果
allOf():当给定的所有CompletableFuture都完成时,返回一个新的CompletableFuture
anyOf():当给定的其中一个CompletableFuture完成时,返回一个新的CompletableFuture

四、结果处理

public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action) 
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action) 
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)

五、异常处理
handle:返回一个新的CompletionStage,当该阶段正常或异常完成时,将使用此阶段的结果和异常作为所提供函数的参数执行,不会将内部异常抛出。
whenComplete:返回与此阶段具有相同结果或异常的新CompletionStage,该阶段在此阶段完成时执行给定操作。与方法handle不同,会将内部异常往外抛出。
exceptionally:返回一个新的CompletableFuture,CompletableFuture提供了异常捕获回调exceptionally,相当于同步调用中的try/catch。

你可能感兴趣的:(java,#,基础,java)