CompletableFuture入门学习

一 CompletableFuture介绍

CompletableFuture是实现异步编程的一种方式,有多种方法创建异步任务,可以编排多个异步任务;
CompletableFuture实现了Future接口和CompletionStage接口,所以有Future接口异步计算的特性和CompletionStage接口异步计算过程和链式调用的特性;

二 CompletableFuture的常用API介绍

CompletableFuture类中的方法非常多,将这些方法按照用途划分为创建异步任务、异步任务的编排、回调处理等类型。
public static CompletableFuture<Void> runAsync(Runnable runnable):
方法参数是Runnable异步任务的接口,使用默认的线程池执行Runnable异步任务,Runnable接口的run方法没有返回值,runAsync方法的返回值是CompletableFuture<Void>空值;
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor):
方法参数是Runnable异步任务的接口,使用自定义线程池执行Runnable异步任务,Runnable接口的run方法没有返回值,runAsync方法的返回值是CompletableFuture<Void>空值;
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier):
方法参数Supplier异步任务接口,使用默认的线程池执行Supplier异步任务,Supplier接口的get方法是有返回值的,supplyAsync方法的返回值是CompletableFuture<U>对象;
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor):
方法参数Supplier异步任务接口,使用自定义线程池的线程执行Supplier异步任务,Supplier接口的get方法是有返回值的,supplyAsync方法的返回值是CompletableFuture<U>对象;
CompletableFuture中的异步任务是通过获取线程池中的线程来执行的,可以使用默认的线程池ForkJoinPool.commonPool执行任务,也可以自定义线程池执行任务,不同的业务类型使用不同的业务线程池,这样可以避免使用同一个线程池造成线程饥饿,从而影响整个系统的性能; 
runAsync方法开启没有返回结果的异步任务,supplyAsync方法开启有返回结果的异步任务;

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn):
CompletableFuture对象的异步任务结果作为参数传给thenApply方法,而且使用同一个线程对象执行thenApply方法里面的线程任务,thenApply方法的作用是处理和转换CompletableFuture对象的异步任务执行结果,方法参数是Function函数式接口,接收T类型参数转换为U类型结果,方法返回泛型类型U类型的CompletableFuture对象;
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn):
CompletableFuture对象的异步任务结果作为参数传给thenApplyAsync方法,使用默认线程池的一个线程对象执行thenApplyAsync方法里面的线程任务,thenApplyAsync方法的作用是处理和转换CompletableFuture对象的异步任务执行结果,方法参数是Function函数式接口,接收T类型参数转换为U类型结果,方法返回泛型类型U类型的CompletableFuture对象;
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor):
CompletableFuture对象的异步任务结果作为参数传给thenApplyAsync方法,使用自定义线程池一个线程对象执行thenApplyAsync方法里面的线程任务,thenApplyAsync方法的作用是处理和转换CompletableFuture对象的异步任务执行结果,方法参数是Function函数式接口,接收T类型参数转换为U类型结果,方法返回泛型类型U类型的CompletableFuture对象;

public CompletableFuture<Void> thenAccept(Consumer<? super T> action):
CompletableFuture对象的异步任务结果作为参数传给thenAccept方法,而且使用同一个线程对象执行thenAccept方法定义的异步任务,方法参数类型是Consumer函数式接口,thenAccept方法只是将CompletableFuture对象的异步任务结果处理消费,thenAccept方法值类型是泛型类型Void的CompletableFuture对象,即不返回异步任务结果;
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action):
CompletableFuture对象的异步任务结果作为参数传给thenAcceptAsync方法,而且使用默认线程池中的一个线程对象执行thenAcceptAsync方法定义的异步任务,方法参数类型是Consumer函数式接口,thenAcceptAsync方法只是将CompletableFuture对象的异步任务结果进行处理消费,thenAcceptAsync方法值类型是泛型类型Void的CompletableFuture对象,即不返回异步任务结果;
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor):
CompletableFuture对象的异步任务结果作为参数传给thenAcceptAsync方法,而且使用自定义线程池中的一个线程对象执行thenAcceptAsync方法定义的异步任务,方法参数类型是Consumer函数式接口,thenAcceptAsync方法只是将CompletableFuture对象的异步任务结果进行处理消费,thenAcceptAsync方法值类型是泛型类型Void的CompletableFuture对象,即不返回异步任务结果;

public CompletableFuture<Void> thenRun(Runnable action):
CompletableFuture对象的异步任务完成后,不会将异步任务结果传给thenRun方法,只是将异步任务完成的动作告知thenRun方法,使用同一线程处理thenRun方法定义的异步任务,thenRun方法值类型是泛型类型Void的CompletableFuture对象,即不返回异步任务结果;
public CompletableFuture<Void> thenRunAsync(Runnable action):
CompletableFuture对象的异步任务完成后,不会将异步任务结果传给thenRunAsync方法,只是将异步任务完成的动作告知thenRunAsync方法,默认线程池的另一线程处理thenAcceptAsync方法定义的异步任务,thenAcceptAsync方法值类型是泛型类型Void的CompletableFuture对象,即不返回异步任务结果;
public CompletableFuture<Void> thenRunAsync(Runnable action, Executor executor):
CompletableFuture对象的异步任务完成后,不会将异步任务结果传给thenRunAsync方法,只是将异步任务完成的动作告知thenRunAsync方法,自定义线程池的线程处理thenAcceptAsync方法定义的异步任务,thenAcceptAsync方法值类型是泛型类型Void的CompletableFuture对象,即不返回异步任务结果;
上述三种异步任务回调,thenApply方法接收异步任务并处理转换成指定类型,thenAccept方法接收异步任务结果仅用于消费,不转换其他数据类型,thenRun方法不接受异步任务结果,这三个方法都可以与上一个异步任务使用同一个线程,也可以使用默认线程池和自定义线程池的线程

public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn):
CompletableFuture对象的异步任务结果作为参数传给thenCompose方法,使用同一个线程对象执行thenCompose方法里面的线程任务,thenCompose方法的作用是将CompletableFuture对象的异步任务执行结果转换成一个新的CompletableFuture对象,方法参数是Function函数式接口,接收T类型参数转换为CompletionStage<U>类型结果,方法返回CompletableFuture<U>对象;
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn):
CompletableFuture对象的异步任务结果作为参数传给thenComposeAsync方法,而且使用默认线程池中的一个线程对象执行thenComposeAsync方法里面的线程任务,thenComposeAsync方法的作用是将CompletableFuture对象的异步任务执行结果转换成一个新的CompletableFuture对象,方法参数是Function函数式接口,接收T类型参数转换为CompletionStage<U>类型结果,方法返回CompletableFuture<U>对象;
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor):
CompletableFuture对象的异步任务结果作为参数传给thenComposeAsync方法,而且使用自定义线程池中的一个线程对象执行thenComposeAsync方法里面的线程任务,thenComposeAsync方法的作用是将CompletableFuture对象的异步任务执行结果转换成一个新的CompletableFuture对象,方法参数是Function函数式接口,接收T类型参数转换为CompletionStage<U>类型结果,方法返回CompletableFuture<U>对象;

public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn):
CompletableFuture对象的和另一个没有依赖关系的CompletableFuture对象的异步任务结果作为参数传递给thenCombine,执行thenCombine方法的线程可以是执行future1的线程对象,也可以是执行future2的线程,thenCombine方法处理future1和future1异步任务结果,并返回一个新的泛型类型的CompletableFuture对象;
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn):
CompletableFuture对象的和另一个没有依赖关系的CompletableFuture对象的异步任务结果作为参数传递给thenCombine方法,然后默认线程池中的一个线程执行thenCombine方法里面定义的线程任务,thenCombine方法的线程任务可以处理future1和future1异步任务结果,并且最后返回一个新的CompletableFuture<V>对象;
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn, Executor executor):
CompletableFuture对象的和另一个没有依赖关系的CompletableFuture对象的异步任务结果作为参数传递给thenCombine方法,然后自定义线程池中的一个线程执行thenCombine方法里面定义的线程任务,thenCombine方法的线程任务可以处理future1和future1异步任务结果,并且最后返回一个新的CompletableFuture<V>对象;
future1调用thenCompose方法,将future1的异步任务结果作为参数传给future2,两个异步任务是有依赖关系的,future1调用thenCombine方法,future1和future2两个异步任务虽说是没有依赖关系,独立运行,但是这两个异步任务的结果可以作为一起配合使用

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs):
allOf静态方法适用于多个并行执行的异步任务,等所有的CompletableFuture异步任务都完成后,可以进一步处理这些异步任务结果,方法参数是多个任意类型的CompletableFuture对象,方法返回值是CompletableFuture<Void>对象;
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs):
anyOf静态方法适用于多个并行执行的异步任务,只要有一个CompletableFuture异步任务完成,就表示anyOf方法执行完成,方法参数是多个任意类型的CompletableFuture对象,方法返回值是CompletableFuture<Object>对象;

public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn):
exceptionally方法用于处理CompletableFuture对象回调链上的异常,通常处于回调链中的最后位置,如果回调链没有异常就不会调用exceptionally方法,如果回调链上任何一处出现异常,就不再执行后面的回调链方法而是直接进入exceptionally方法处理异常;
exceptionally方法参数是Function<Throwable, ? extends T>,Function的方法T apply(Throwable)其方法参数Function的第二个泛型类型是方法调用者CompletableFuture对象的泛型类型,这样就可以保证调用链没有异常返回的结果类型和有异常返回的结果类型是一致的;
exceptionally方法在回调链中的位置,可以在中间处理异常信息后继续将回调向后执行,也可以在最后位置处理异常信息,通常是在回调链中的最后位置;
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn):
handle方法用于处理CompletableFuture对象回调链上的异常,通常处于回调链中的最后位置,无论回调链上的异步任务是否出现异常,handle方法都会执行;
handle方法参数是BiFunction<? super T, Throwable, ? extends U> fn),BiFunction接口的方法是
U apply(Throwable, T),其方法参数BiFunction的第一个泛型类型是方法调用者CompletableFuture对象的泛型类型,第三个泛型类型是handle方法返回值类型;
handle((T, Throwable) -> {})方法接收的参数有异步任务结果和异步任务异常信息,如果调用链没有出现异常,那么T不为null,Throwable为null,如果调用链出现异常,那么T为null,Throwable不为null;
handle方法在回调链中的位置,可以在中间位置继续将回调向后执行,也可以在最后位置,通常是在回调链中的最后位置;
handle方法默认和方法调用者CompletableFuture对象使用同一个线程对象执行异步任务;
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn):
handleAsync方法在默认线程池中另取一个线程执行异步任务;
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor):
handleAsync方法在自定义线程池中取一个线程执行异步任务;
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action):
whenComplete方法用于处理CompletableFuture对象回调链上的异常,通常处于回调链中的最后位置,无论回调链上的异步任务是否出现异常,whenComplete方法都会执行;
whenComplete方法参数是BiConsumer<? super T, ? super Throwable> action,BiConsumer接口的方法是void accept(T t, Throwable throw),其方法参数BiConsumer的第一个泛型类型是方法调用者CompletableFuture对象的泛型类型,方法没有返回值;
whenComplete((T, Throwable) -> {})方法接收的参数有异步任务结果和异步任务异常信息,如果调用链没有出现异常,那么T不为null,Throwable为null,如果调用链出现异常,那么Throwable不为null,T为null;
whenComplete方法在回调链中的位置,可以在中间位置继续将回调向后执行,也可以在最后位置,通常是在回调链中的最后位置;​​​​​​​
whenComplete方法默认和方法调用者CompletableFuture对象使用同一个线程对象执行异步任务;
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action):
whenCompleteAsync方法在默认线程池中另取一个线程执行异步任务;​​​​​​​
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor):
whenCompleteAsync方法在自定义线程池中取一个线程执行异步任务;
处理CompletableFuture对象回调链上的异常的方法有exceptionally、handle和whenComplete方法,处理异常的方法通常处于回调链中的最后位置:
exceptionally方法,如果回调链没有异常就不会调用exceptionally方法,如果回调链上任何一处出现异常,就不再执行后面的回调链方法而是直接进入exceptionally方法处理异常;
handle方法,无论回调链上的异步任务是否出现异常,handle方法都会执行;
whenComplete方法,无论回调链上的异步任务是否出现异常,whenComplete方法都会执行;

public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn):
CompletableFuture对象一的applyToEither方法参数是CompletableFuture对象二和Function函数式接口对象,future1和future2其中一个异步任务先执行完成,另一个异步任务也不再执行,而是直接执行Function函数,Function函数接收最先执行完成的异步任务结果,方法返回值类型是根据需求自定义类型;
applyToEither方法返回值是CompletableFuture<U>对象;
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn):
applyToEitherAsync方法在默认线程池中另取一个线程执行异步任务;​​​​​​​
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn, Executor executor):
applyToEitherAsync方法在自定义线程池中取一个线程执行异步任务;

public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action):
CompletableFuture对象一的acceptEither方法参数是CompletableFuture对象二和Consumer函数式接口对象,future1和future2其中一个异步任务先执行完成,另一个异步任务也不再执行,而是直接执行Consumer函数,Consumer函数接收最先执行完成的异步任务结果,不返回值;
acceptEither方法返回值是CompletableFuture<Void>对象;
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action):
acceptEitherAsync方法在默认线程池中另取一个线程执行异步任务;​​​​​​​
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor):
acceptEitherAsync方法在自定义线程池中取一个线程执行异步任务;
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other, Runnable action):
CompletableFuture对象一的runAfterEither方法参数是CompletableFuture对象二和Runnable函数式接口对象,future1和future2其中一个异步任务先执行完成,另一个异步任务也不再执行,而是直接执行Runnable函数,Runnable函数只是接收异步任务完成的通知,并不会处理异步任务的结果,不返回值;
runAfterEither方法返回值是CompletableFuture<Void>对象;
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action):
runAfterEitherAsync方法在默认线程池中另取一个线程执行异步任务;​​​​​​​
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action, Executor executor):
runAfterEitherAsync方法在自定义线程池中取一个线程执行异步任务;
CompletableFuture对象一和CompletableFuture对象二对比哪个异步任务先执行完成,然后执行后续的操作有applyToEither、acceptEither和runAfterEither三种方法:
applyToEither方法会接收最先执行完成的异步任务结果,然后返回CompletableFuture<U>对象,即指定泛型类型的对象,而且要求比较的两个CompletableFuture对象泛型类型一致或其父类型一致;
acceptEither方法会接收最先执行完成的异步任务结果,然后返回CompletableFuture<Void>对象,而且要求比较的两个CompletableFuture对象泛型类型一致或其父类型一致;
runAfterEither方法只会接收最先执行完成的异步任务的通知,然后返回CompletableFuture<U>对象,没有要求比较的两个CompletableFuture对象泛型类型一致或其父类型一致;

public T join():以阻塞的方式获取异步结果,会抛出运行时异常,程序可以不用处理,适用于流式编程;
public T get():以阻塞的方式获取异步结果,会抛出编译时异常,程序必须要处理,不适用流式编程;
public T get(long timeout, TimeUnit unit):以等待超时的阻塞方式获取异步结果,会抛出编译时异常,程序必须要处理,不适用流式编程;

三 CompletableFuture的常用API演示

3.1 创建异步任务

使用静态方法runAsync(Runnable runnable)和supplyAsync(Supplier<U> supplier)创建异步任务

3.1.1 runAsync

public static CompletableFuture<Void> runAsync(Runnable runnable),方法参数是Runnable函数式接口,接口定义如下:
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
runAsync方法创建线程异步任务,可以使用默认的线程池处理异步任务,也可以使用自定义线程池处理异步任务,runAsync方法返回值是泛型类型Void的CompletableFuture对象,即不返回异步任务结果

public class FileUtils {

    public static String readFile(String filePath) {
        InputStream is = CompletableFutureDemo.class.getClassLoader().getResourceAsStream(filePath);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
        StringBuffer sb = new StringBuffer();
        String str;
        while (true) {
            try {
                if (((str = bufferedReader.readLine()) != null)) {
                    sb.append(str).append("\r\n");
                } else {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.substring(0, sb.length() - 2);
    }

    public static String currentThread() {
        return Thread.currentThread().getName();
    }
    
    public static void sleep(long time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
hello.txt
    玫瑰,水仙,牡丹
hello_zero.txt
    No sweet without sweat
public static void main(String[] args) throws InterruptedException {
    CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("当前工作的线程是: " + FileUtils.currentThread());
        String str = FileUtils.readFile("hello.txt");
        System.out.println("读取到的文件内容是: \r\n" + str);
    });
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    try {
        CompletableFuture<Void> runAsync2 = CompletableFuture.runAsync(() -> {
            // 模拟线程任务, 读取hello.txt文件
            System.out.println("当前工作的线程是: " + FileUtils.currentThread());
            String str = FileUtils.readFile("hello.txt");
            System.out.println("读取到的文件内容是: \r\n" + str);
        }, executorService);
    } finally {
        executorService.shutdown();
    }
    // 等待异步任务执行完成
    Thread.sleep(1000);
}

3.1.2 supplyAsync

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier),方法参数Supplier函数式接口,接口定义如下:
@FunctionalInterface
public interface Supplier<T> {
    T get();
}
supplyAsync方法创建线程异步任务,可以使用默认的线程池处理异步任务,也可以使用自定义线程池处理异步任务,supplyAsync方法返回值是指定泛型类型的CompletableFuture对象

public static void main(String[] args) throws InterruptedException, ExecutionException {
    CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("当前工作的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    });
    String resultStr1 = supplyAsync.get();
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    try {
        CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
            // 模拟线程任务, 读取hello.txt文件
            System.out.println("当前工作的线程是: " + FileUtils.currentThread());
            return FileUtils.readFile("hello.txt");
        }, executorService);
        String resultStr2 = supplyAsync2.get();
    } finally {
        executorService.shutdown();
    }
    // 等待异步任务执行完成
    Thread.sleep(1000);
}

通常情况下,用户线程在任务执行完成后,线程对象就会自动退出,线程对象等待垃圾回收器回收,而守护线程会随着父线程的结束而关闭,哪怕守护线程任务还未执行完成;
线程池中的线程在任务执行完成任务后,不会去销毁,而是处于等待状态,直到再分配到线程任务执行,CompletableFuture的异步任务默认使用ForkJoinPool.commonPool线程池里面的线程来完成的,当异步任务执行完成再把线程归还给线程池,ForkJoinPool.commonPool线程池归主线程管理,主线程结束,默认的线程池也会关闭;
CompletableFuture自定义线程池的生命周期就属于开发者自己管理,在结束主线程的时候需要手动关闭自定义线程池;

3.2 异步任务回调

3.2.1 thenApply

CompletableFuture异步任务执行完成后,调用thenApply方法是将异步任务结果转换为指定类型对象,方法参数是Function函数式接口,接口方法如下:
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
thenApply方法返回值是指定泛型类型的CompletableFuture对象

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn):

public static void main(String[] args) throws InterruptedException, ExecutionException {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("supplyAsync方法当前工作的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    });
    CompletableFuture<Map<String, Integer>> future2 = future1.thenApply(str -> {
        Map<String, Integer> map = new HashMap<>();
        Random random = new Random();
        String[] strArr = str.replaceAll("\\s*", "").split(",");
        for (String s : strArr) {
            map.put(s, random.nextInt(10));
        }
        System.out.println("thenApply方法当前工作的线程是: " + FileUtils.currentThread());
        return map;
    });
    // future1对象的异步任务结果作为参数传给thenApply方法
    // 使用同一个线程对象处理supplyAsync方法和thenApply方法定义的线程异步任务
    Map<String, Integer> resultMap = future2.get();
    System.out.println("resultMap is: " + resultMap);
    // supplyAsync方法当前工作的线程是: ForkJoinPool.commonPool-worker-1
    // thenApply方法当前工作的线程是: ForkJoinPool.commonPool-worker-1
    // resultMap is: {牡丹=0, 水仙=7, 玫瑰=9}
}

public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn):

public static void main(String[] args) throws InterruptedException, ExecutionException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<Map<String, Integer>> future = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("supplyAsync方法当前工作的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    }, executorService).thenApplyAsync(str -> {
        Map<String, Integer> map = new HashMap<>();
        Random random = new Random();
        String[] strArr = str.replaceAll("\\s*", "").split(",");
        for (String s : strArr) {
            map.put(s, random.nextInt(10));
        }
        System.out.println("thenApplyAsync方法当前工作的线程是: " + FileUtils.currentThread());
        return map;
    });
    executorService.shutdown();
    /**
     * supplyAsync方法的异步任务结果作为参数传给thenApplyAsync方法
     * 默认线程池另取一个线程对象处理thenApplyAsync方法定义的线程异步任务
     * 有时候为了提高性能, 默认线程池使用同一个线程对象处理supplyAsync方法
     * 和thenApplyAsync方法定义的异步线程任务
     */
    Map<String, Integer> resultMap = future.get();
    System.out.println("resultMap is: " + resultMap);
    // supplyAsync方法当前工作的线程是: pool-1-thread-1
    // thenApplyAsync方法当前工作的线程是: ForkJoinPool.commonPool-worker-1
    // resultMap is: {牡丹=0, 水仙=3, 玫瑰=0}
}

public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor):

public static void main(String[] args) throws InterruptedException, ExecutionException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<Map<String, Integer>> future = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("supplyAsync方法当前工作的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    }, executorService).thenApplyAsync(str -> {
        Map<String, Integer> map = new HashMap<>();
        Random random = new Random();
        String[] strArr = str.replaceAll("\\s*", "").split(",");
        for (String s : strArr) {
            map.put(s, random.nextInt(10));
        }
        System.out.println("thenApplyAsync方法当前工作的线程是: " + FileUtils.currentThread());
        return map;
    }, executorService);
    // supplyAsync方法的异步任务结果作为参数传给thenApplyAsync方法
    // 使用自定义线程池中的一个线程对象处理thenApplyAsync方法定义的线程异步任务
    Map<String, Integer> resultMap = future.get();
    System.out.println("resultMap is: " + resultMap);
    // supplyAsync方法当前工作的线程是: pool-1-thread-1
    // thenApplyAsync方法当前工作的线程是: pool-1-thread-2
    // resultMap is: {牡丹=8, 水仙=3, 玫瑰=2}
    executorService.shutdown();
}

3.2.2 thenAccept

CompletableFuture异步任务执行完成后,调用thenAccept方法将异步任务结果仅消费使用,方法参数是Consumer函数式接口,接口方法如下:
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
thenAccept方法返回值是泛型类型Void的CompletableFuture对象,即不返回异步任务结果

public CompletableFuture<Void> thenAccept(Consumer<? super T> action)

public static void main(String[] args) {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("supplyAsync方法当前工作的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    });
    CompletableFuture<Void> future2 = future1.thenAccept(str -> {
        Map<String, Integer> map = new HashMap<>();
        Random random = new Random();
        String[] strArr = str.replaceAll("\\s*", "").split(",");
        for (String s : strArr) {
            map.put(s, random.nextInt(10));
        }
        System.out.println("thenAccept方法当前工作的线程是: " + FileUtils.currentThread());
        System.out.println("map is: " + map);
    });
    /*
     * supplyAsync方法创建的CompletableFuture对象的异步任务结果交于thenAccept方法处理
     * 使用同一线程处理thenAccept方法定义的线程异步任务, thenAccept方法不返回异步处理结果
     */
    // supplyAsync方法当前工作的线程是: ForkJoinPool.commonPool-worker-1
    // thenAccept方法当前工作的线程是: ForkJoinPool.commonPool-worker-1
    // map is: {牡丹=6, 水仙=6, 玫瑰=7}

    // 主线程休眠一段时间, 让异步线程任务执行完成
    FileUtils.sleep(1000);
}

public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("supplyAsync方法当前工作的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    }, executorService).thenAcceptAsync(str -> {
        Map<String, Integer> map = new HashMap<>();
        Random random = new Random();
        String[] strArr = str.replaceAll("\\s*", "").split(",");
        for (String s : strArr) {
            map.put(s, random.nextInt(10));
        }
        System.out.println("thenAcceptAsync方法当前工作的线程是: " + FileUtils.currentThread());
        System.out.println("map is: " + map);
    });
    /*
     * supplyAsync方法创建的CompletableFuture对象异步任务
     * 异步任务的执行结果交于thenAcceptAsync方法处理
     * 使用默认线程池中的一个线程处理thenAccept方法定义的线程异步任务
     * 有时候为了提高性能, 默认线程池使用同一个线程对象处理supplyAsync方法
     * 和thenAcceptAsync方法
     * 定义的线程异步任务, thenAcceptAsync方法不返回异步处理结果
     *
     */
    // supplyAsync方法当前工作的线程是: pool-1-thread-1
    // thenAcceptAsync方法当前工作的线程是: ForkJoinPool.commonPool-worker-1
    // map is: {牡丹=8, 水仙=3, 玫瑰=3}

    // 主线程休眠一段时间, 让异步线程任务执行完成
    FileUtils.sleep(1000);
    executorService.shutdown();
}

public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("supplyAsync方法当前工作的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    }, executorService).thenAcceptAsync(str -> {
        Map<String, Integer> map = new HashMap<>();
        Random random = new Random();
        String[] strArr = str.replaceAll("\\s*", "").split(",");
        for (String s : strArr) {
            map.put(s, random.nextInt(10));
        }
        System.out.println("thenAcceptAsync方法当前工作的线程是: " + FileUtils.currentThread());
        System.out.println("map is: " + map);
    }, executorService);
    /*
    * supplyAsync方法创建的CompletableFuture对象的异步任务结果交于thenAcceptAsync方法处理
    * 使用自定义线程池中的一个线程处理thenAcceptAsync方法定义的线程异步任务
    * thenAcceptAsync方法不返回异步处理结果
    */
    // supplyAsync方法当前工作的线程是: pool-1-thread-1
    // thenAcceptAsync方法当前工作的线程是: pool-1-thread-2
    // map is: {牡丹=3, 水仙=0, 玫瑰=6}

    // 主线程休眠一段时间, 让异步线程任务执行完成
    FileUtils.sleep(1000);
    executorService.shutdown();
}

3.3.3 thenRun

CompletableFuture对象的异步任务完成后,不会将异步任务结果传给thenRun方法,只是将异步任务完成的动作告知thenRun方法定义的异步任务,方法参数是Runnable函数式接口,接口方法如下:
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
thenRun方法返回值是泛型类型Void的CompletableFuture对象,即不返回异步任务结果

public CompletableFuture<Void> thenRun(Runnable action)

public static void main(String[] args) {
    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("supplyAsync方法当前工作的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    }).thenRun(() -> {
        System.out.println("thenRun方法当前工作的线程是: " + FileUtils.currentThread());
        System.out.println("异步任务完成之后的后续操作");
    });
    /**
     * supplyAsync方法创建的CompletableFuture异步任务执行完成后的动作, 告知thenRun方法
     * 使用默认线程池的另一个线程执行thenRun方法定义的线程任务
     * thenRun方法不处理上一个CompletableFuture对象的执行结果
     * thenRun方法不返回异步任务处理结果
     */
    // supplyAsync方法当前工作的线程是: ForkJoinPool.commonPool-worker-1
    // thenRun方法当前工作的线程是: ForkJoinPool.commonPool-worker-1
    // 异步任务完成之后的后续操作
    // 主线程休眠一段时间, 让异步线程任务执行完成
    FileUtils.sleep(1000);
}

public CompletableFuture<Void> thenRunAsync(Runnable action)

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("supplyAsync方法当前工作的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    }, executorService).thenRunAsync(() -> {
        System.out.println("thenRunAsync方法当前工作的线程是: " + FileUtils.currentThread());
        System.out.println("异步任务完成之后的后续操作");
    });
    /**
     * supplyAsync方法创建的CompletableFuture异步任务执行完成后的动作, 告知thenRunAsync方法
     * 使用默认线程池的另一个线程执行thenRunAsync方法定义的线程任务
     * thenRunAsync方法不处理上一个CompletableFuture对象的执行结果
     * thenRunAsync方法不返回异步任务处理结果
     */
    // supplyAsync方法当前工作的线程是: pool-1-thread-1
    // thenRunAsync方法当前工作的线程是: ForkJoinPool.commonPool-worker-1
    // 异步任务完成之后的后续操作
    // 主线程休眠一段时间, 让异步线程任务执行完成
    FileUtils.sleep(1000);
    executorService.shutdown();
}

public CompletableFuture<Void> thenRunAsync(Runnable action, Executor executor)

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("supplyAsync方法当前工作的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    }, executorService).thenRunAsync(() -> {
        System.out.println("thenRunAsync方法当前工作的线程是: " + FileUtils.currentThread());
        System.out.println("异步任务完成之后的后续操作");
    }, executorService);
    /**
     * supplyAsync方法创建的CompletableFuture异步任务执行完成后的动作, 告知thenRunAsync方法
     * 使用自定义线程池的线程执行thenRunAsync方法定义的线程任务
     * thenRunAsync方法不处理上一个CompletableFuture对象的执行结果
     * thenRunAsync方法不返回异步任务处理结果
     */
    // supplyAsync方法当前工作的线程是: pool-1-thread-1
    // thenRunAsync方法当前工作的线程是: pool-1-thread-2
    // 异步任务完成之后的后续操作
    // 主线程休眠一段时间, 让异步线程任务执行完成
    FileUtils.sleep(1000);
    executorService.shutdown();
}

3.3 异步任务编排

3.3.1 thenCompose

CompletableFuture对象的异步任务执行完成后,将异步任务结果作为参数传给thenCompose方法,方法参数是Function函数式接口Function<? super T, ? extends CompletionStage<U>> fn)
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
thenCompose方法的返回值是CompletableFuture<U>类型;
thenCompose方法连接两个有依赖关系的CompletableFuture对象,把上一个CompletableFuture对象的异步任务结果作为参数传递给thenCompose方法里面定义的CompletableFuture对象;

public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("执行supplyAsync方法的工作线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    }, executorService);
    CompletableFuture<Map<String, Integer>> future2 = future1.thenCompose(str -> {
        System.out.println("接收到上一个异步任务结果的参数: " + str);
        System.out.println("执行thenCompose方法的工作线程是: " + FileUtils.currentThread());
        return CompletableFuture.supplyAsync(() -> {
            // 使用默认线程池中的另一线程执行任务, 也可以使用自定义线程池执行任务
            System.out.println("执行supplyAsync方法的工作线程是: " + FileUtils.currentThread());
            Map<String, Integer> map = new HashMap<>();
            Random random = new Random();
            String[] strArr = str.replaceAll("\\s*", "").split(",");
            for (String s : strArr) {
                map.put(s, random.nextInt(10));
            }
            return map;
        });
    });
    Map<String, Integer> resultMap = future2.get();
    System.out.println("异步任务的执行结果是: " + resultMap);
    // 执行supplyAsync方法的工作线程是: pool-1-thread-1
    // 接收到上一个异步任务结果的参数: 玫瑰,水仙,牡丹
    // 执行thenCompose方法的工作线程是: pool-1-thread-1
    // 执行supplyAsync方法的工作线程是: ForkJoinPool.commonPool-worker-1
    // 异步任务的执行结果是: {牡丹=9, 水仙=7, 玫瑰=7}

    // 模拟主线程休眠, 让异步线程任务执行
    FileUtils.sleep(1000);
    executorService.shutdown();
}

public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn)

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<Map<String, Integer>> future1 = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("执行supplyAsync方法的工作线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    }, executorService).thenComposeAsync(str -> {
        System.out.println("接收到上一个异步任务结果的参数: " + str);
        System.out.println("执行thenCompose方法的工作线程是: " + FileUtils.currentThread());
        return CompletableFuture.supplyAsync(() -> {
            // 使用默认线程池中的另一线程执行任务, 也可以使用自定义线程池执行任务
            System.out.println("执行supplyAsync方法的工作线程是: " + FileUtils.currentThread());
            Map<String, Integer> map = new HashMap<>();
            Random random = new Random();
            String[] strArr = str.replaceAll("\\s*", "").split(",");
            for (String s : strArr) {
                map.put(s, random.nextInt(10));
            }
            return map;
        });
    });
    Map<String, Integer> resultMap = future1.get();
    System.out.println("异步任务的执行结果是: " + resultMap);
    // 执行supplyAsync方法的工作线程是: pool-1-thread-1
    // 接收到上一个异步任务结果的参数: 玫瑰,水仙,牡丹
    // 执行thenCompose方法的工作线程是: ForkJoinPool.commonPool-worker-1
    // 执行supplyAsync方法的工作线程是: ForkJoinPool.commonPool-worker-1
    // 异步任务的执行结果是: {牡丹=3, 水仙=6, 玫瑰=4}

    // 模拟主线程休眠, 让异步线程任务执行
    FileUtils.sleep(1000);
    executorService.shutdown();
}

public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor)

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<Map<String, Integer>> future1 = CompletableFuture.supplyAsync(() -> {
        // 模拟线程任务, 读取hello.txt文件
        System.out.println("执行supplyAsync方法的工作线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    }, executorService).thenComposeAsync(str -> {
        System.out.println("接收到上一个异步任务结果的参数: " + str);
        System.out.println("执行thenCompose方法的工作线程是: " + FileUtils.currentThread());
        return CompletableFuture.supplyAsync(() -> {
            // 使用默认线程池中的另一线程执行任务, 也可以使用自定义线程池执行任务
            System.out.println("执行supplyAsync方法的工作线程是: " + FileUtils.currentThread());
            Map<String, Integer> map = new HashMap<>();
            Random random = new Random();
            String[] strArr = str.replaceAll("\\s*", "").split(",");
            for (String s : strArr) {
                map.put(s, random.nextInt(10));
            }
            return map;
        });
    }, executorService);
    Map<String, Integer> resultMap = future1.get();
    System.out.println("异步任务的执行结果是: " + resultMap);
    // 执行supplyAsync方法的工作线程是: pool-1-thread-1
    // 接收到上一个异步任务结果的参数: 玫瑰,水仙,牡丹
    // 执行thenCompose方法的工作线程是: pool-1-thread-2
    // 执行supplyAsync方法的工作线程是: ForkJoinPool.commonPool-worker-1
    // 异步任务的执行结果是: {牡丹=7, 水仙=0, 玫瑰=3}

    // 模拟主线程休眠, 让异步线程任务执行
    FileUtils.sleep(1000);
    executorService.shutdown();
}

3.3.2 thenCombine

两个没有依赖关系的CompletableFuture对象,独立完成异步任务后,才执行thenCombine回调方法,将这两个异步任务结果作为参数传递给thenCombine方法做进一步处理,thenCombine方法参数是CompletionStage<? extends U> other和BiFunction<? super T,? super U,? extends V> fn
@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T t, U u); 
}
BiFunction接口的apply方法参数T指当前CompletableFuture对象,U指other的CompletableFuture对象,R指处理这两个异步任务结果后返回的类型
thenCombine方法的返回值是CompletableFuture<V>对象;

public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn):

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("读取hello.txt文件的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    });
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("读取hello_zero.txt文件的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello_zero.txt");
    });
    CompletableFuture<String> future3 = future1.thenCombine(future2, (str1, str2) -> {
        // 拼接两个异步任务读取到的文件内容
        String result = str1.concat("\r\n").concat(str2);
        System.out.println("执行拼接任务的线程是: " + FileUtils.currentThread());
        return result;
    });
    String result = future3.get();
    System.out.println("result is: \r\n" + result);
    /**
     * future1和future2的异步执行完成后, 才调用thenCombine方法, 
     * 将future1和future2的异步执行结果交给thenCombine方法处理
     * 执行thenCombine回调函数的线程, 可以是执行future1的线程
     * 也可以是执行future2的线程
     */
    // 读取hello.txt文件的线程是: ForkJoinPool.commonPool-worker-1
    // 读取hello_zero.txt文件的线程是: ForkJoinPool.commonPool-worker-2
    // 执行拼接任务的线程是: ForkJoinPool.commonPool-worker-1
    // result is:
    // 玫瑰,水仙,牡丹
    // No sweet without sweat
}

public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn):

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("读取hello.txt文件的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    });
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("读取hello_zero.txt文件的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello_zero.txt");
    });
    CompletableFuture<String> future3 = future1.thenCombineAsync(future2, (str1, str2) -> {
        // 拼接两个异步任务读取到的文件内容
        String result = str1.concat("\r\n").concat(str2);
        System.out.println("执行拼接任务的线程是: " + FileUtils.currentThread());
        return result;
    });
    String result = future3.get();
    System.out.println("result is: \r\n" + result);
    /**
     * future1和future2的异步执行完成后, 才调用thenCombineAsync方法,
     * 将future1和future2的异步执行结果交给thenCombineAsync方法处理
     * 执行thenCombineAsync回调函数的线程是默认线程池的一个线程
     * 为了提高程序的效率, 执行thenCombineAsync回调函数的线程,可以是
     * 执行future1的线程, 也可以是执行future2的线程
     */
    // 读取hello.txt文件的线程是: ForkJoinPool.commonPool-worker-1
    // 读取hello_zero.txt文件的线程是: ForkJoinPool.commonPool-worker-2
    // 执行拼接任务的线程是: ForkJoinPool.commonPool-worker-1
    // result is:
    // 玫瑰,水仙,牡丹
    // No sweet without sweat
}

public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn, Executor executor):

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("读取hello.txt文件的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello.txt");
    });
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("读取hello_zero.txt文件的线程是: " + FileUtils.currentThread());
        return FileUtils.readFile("hello_zero.txt");
    });
    CompletableFuture<String> future3 = future1.thenCombineAsync(future2, (str1, str2) -> {
        // 拼接两个异步任务读取到的文件内容
        String result = str1.concat("\r\n").concat(str2);
        System.out.println("执行拼接任务的线程是: " + FileUtils.currentThread());
        return result;
    }, executorService);
    String result = future3.get();
    System.out.println("result is: \r\n" + result);
    /**
     * future1和future2的异步执行完成后, 才调用thenCombineAsync方法,
     * 将future1和future2的异步执行结果交给thenCombineAsync方法处理
     * 执行thenCombineAsync回调函数的线程是自定义线程池的一个线程
     */
    // 读取hello.txt文件的线程是: ForkJoinPool.commonPool-worker-1
    // 读取hello_zero.txt文件的线程是: ForkJoinPool.commonPool-worker-2
    // 执行拼接任务的线程是: pool-1-thread-1
    // result is:
    // 玫瑰,水仙,牡丹
    // No sweet without sweat
    executorService.shutdown();
}

3.3.3 allOf

allOf方法适用于多个并行执行的异步任务,等所有的异步任务都完成后,可以进一步处理这些异步任务结果

public static void main(String[] args) throws ExecutionException, InterruptedException {
    System.out.println(printMsg() + " 主线程任务开始执行...");
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + " 执行任务一...");
        // 模拟耗时操作
        FileUtils.sleep(2000);
        return "futureOneResult";
    });
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + " 执行任务二...");
        // 模拟耗时操作
        FileUtils.sleep(3000);
        return "futureTwoResult";
    });
    CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + " 执行任务三...");
        // 模拟耗时操作
        FileUtils.sleep(1000);
        return "futureThreeResult";
    });
    // CompletableFuture.allOf方法使用或不使用, 好像没太多的关系
    // CompletableFuture.allOf(future1, future2, future3);
    String s1 = future1.get();
    System.out.println(printMsg() + " | future1执行结果是: " + s1);
    String s2 = future2.get();
    System.out.println(printMsg() + " | future2执行结果是: " + s2);
    String s3 = future3.get();
    System.out.println(printMsg() + " | future3执行结果是: " + s3);
    System.out.println(printMsg() + " 主线程任务继续执行...");
    System.out.println("future1.isDone() = " + future1.isDone());
    System.out.println("future2.isDone() = " + future2.isDone());
    System.out.println("future3.isDone() = " + future3.isDone());
    /**
     * CompletableFuture.allOf方法使用了
     * main  | 23:43:19 主线程任务开始执行...
     * ForkJoinPool.commonPool-worker-1  | 23:43:19 执行任务一...
     * ForkJoinPool.commonPool-worker-2  | 23:43:19 执行任务二...
     * ForkJoinPool.commonPool-worker-3  | 23:43:19 执行任务三...
     * main  | 23:43:21 | future1执行结果是: futureOneResult
     * main  | 23:43:22 | future2执行结果是: futureTwoResult
     * main  | 23:43:22 | future3执行结果是: futureThreeResult
     * main  | 23:43:22 主线程任务继续执行...
     * future1.isDone() = true
     * future2.isDone() = true
     * future3.isDone() = true
     * 
     * CompletableFuture.allOf方法没使用
     * main  | 23:45:02 主线程任务开始执行...
     * ForkJoinPool.commonPool-worker-1  | 23:45:02 执行任务一...
     * ForkJoinPool.commonPool-worker-2  | 23:45:02 执行任务二...
     * ForkJoinPool.commonPool-worker-3  | 23:45:02 执行任务三...
     * main  | 23:45:04 | future1执行结果是: futureOneResult
     * main  | 23:45:05 | future2执行结果是: futureTwoResult
     * main  | 23:45:05 | future3执行结果是: futureThreeResult
     * main  | 23:45:05 主线程任务继续执行...
     * future1.isDone() = true
     * future2.isDone() = true
     * future3.isDone() = true
     */
}

上述案例使用CompletableFuture.allOf静态方法对异步任务的执行好像没有太多的关系,对比下使用allOf方法和不使用allOf方法的执行结果,执行逻辑是一样的;
当多个CompletableFuture对象异步任务并行执行时,每个异步任务都可以通过get()或join()方法阻塞父线程,直到当前CompletableFuture对象异步任务执行完成,这样可能会阻塞其他异步任务结果的获取,还有的是异步任务不需要获取执行结果,也就不调用get()和join()方法,但是也需要保证异步任务执行完成;
allOf方法的参数是CompletableFuture对象数组,可以是有返回值的CompletableFuture<U>对象,也可以是无返回值的CompletableFuture<Void>对象;
allOf方法的返回值是CompletableFuture<Void>对象,即是null值的CompletableFuture对象,所以拥有包括get()和join()在内的所有方法,get()和join()都是会阻塞父线程,直到CompletableFuture对象的异步任务执行完成;
所以综上所述,allOf方法的可以接收有返回值类型的CompletableFuture<U>对象和无返回值类型的CompletableFuture<Void>对象,然后调用get()或join()方法阻塞父线程,即是等到allOf方法里面的所有异步任务都执行完成,父线程才会继续执行,这是父线程可以任意使用执行完成的异步任务的结果;

public static void main(String[] args) throws ExecutionException, InterruptedException {
    System.out.println(printMsg() + " 主线程任务开始执行...");
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + " 执行任务一...");
        // 模拟耗时操作
        FileUtils.sleep(2000);
        return "futureOneResult";
    });
    CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
        System.out.println(printMsg() + " 执行任务二...");
        // 模拟耗时操作
        FileUtils.sleep(8000);
    });
    CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + " 执行任务三...");
        // 模拟耗时操作
        FileUtils.sleep(1000);
        return "futureThreeResult";
    });
    CompletableFuture.allOf(future1, future2, future3).get();
    Map<String, String> map = new HashMap<>();
    map.put("future1", future1.get());
    map.put("future3", future3.get());
    System.out.println(printMsg() + " 主线程任务继续执行...");
    System.out.println("future1.isDone() = " + future1.isDone());
    System.out.println("future2.isDone() = " + future2.isDone());
    System.out.println("future3.isDone() = " + future3.isDone());
    System.out.println("map result is: " + map);
    /**
     * 不使用CompletableFuture.allOf().get()方法
     * main  | 00:34:59 主线程任务开始执行...
     * ForkJoinPool.commonPool-worker-1  | 00:34:59 执行任务一...
     * ForkJoinPool.commonPool-worker-2  | 00:34:59 执行任务二...
     * ForkJoinPool.commonPool-worker-3  | 00:34:59 执行任务三...
     * main  | 00:35:01 主线程任务继续执行...
     * future1.isDone() = true
     * future2.isDone() = false
     * future3.isDone() = true
     * map result is: {future1=futureOneResult, future3=futureThreeResult}
     *
     * 使用CompletableFuture.allOf().get()方法
     * main  | 00:35:23 主线程任务开始执行...
     * ForkJoinPool.commonPool-worker-1  | 00:35:23 执行任务一...
     * ForkJoinPool.commonPool-worker-2  | 00:35:23 执行任务二...
     * ForkJoinPool.commonPool-worker-3  | 00:35:23 执行任务三...
     * main  | 00:35:31 主线程任务继续执行...
     * future1.isDone() = true
     * future2.isDone() = true
     * future3.isDone() = true
     * map result is: {future1=futureOneResult, future3=futureThreeResult}
     */
}

CompletableFuture.allOf(future1, future2, future3).get()方法会阻塞主线程,直到allOf方法里面的所有异步任务执行完成,主线程才会继续执行,这时在主线程中就可以future.get()方法直接获取异步执行结果,处理这些异步任务结果。

3.3.4 anyOf

anyOf静态方法适用于多个并行执行的异步任务,只要有一个CompletableFuture异步任务完成,就表示anyOf方法执行完成

public static void main(String[] args) throws ExecutionException, InterruptedException {
    System.out.println(printMsg() + " 主线程任务开始执行...");
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + " 执行任务一...");
        // 模拟耗时操作
        FileUtils.sleep(2000);
        return "futureOneResult";
    });
    CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
        System.out.println(printMsg() + " 执行任务二...");
        // 模拟耗时操作
        FileUtils.sleep(8000);
    });
    CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + " 执行任务三...");
        // 模拟耗时操作
        FileUtils.sleep(1000);
        return 10086;
    });
    CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2, future3);
    Object obj = anyOfFuture.get();
    System.out.println(printMsg() + " 主线程任务继续执行...");
    System.out.println("anyOf result is: " + obj);
    System.out.println("future1.isDone() = " + future1.isDone());
    System.out.println("future2.isDone() = " + future2.isDone());
    System.out.println("future3.isDone() = " + future3.isDone());
    /**
     * 不使用CompletableFuture.allOf().get()方法
     * main  | 07:23:49 主线程任务开始执行...
     * ForkJoinPool.commonPool-worker-1  | 07:23:49 执行任务一...
     * ForkJoinPool.commonPool-worker-2  | 07:23:49 执行任务二...
     * ForkJoinPool.commonPool-worker-3  | 07:23:49 执行任务三...
     * main  | 07:23:49 主线程任务继续执行...
     * future1.isDone() = false
     * future2.isDone() = false
     * future3.isDone() = false
     *
     * 使用CompletableFuture.allOf().get()方法
     * main  | 07:40:01 主线程任务开始执行...
     * ForkJoinPool.commonPool-worker-1  | 07:40:01 执行任务一...
     * ForkJoinPool.commonPool-worker-2  | 07:40:01 执行任务二...
     * ForkJoinPool.commonPool-worker-3  | 07:40:01 执行任务三...
     * main  | 07:40:02 主线程任务继续执行...
     * anyOf result is: 10086
     * future1.isDone() = false
     * future2.isDone() = false
     * future3.isDone() = true
     */
}

如果不使用anyOf方法并行处理这三个异步任务,那么在主线程没有耗时操作的情况下,这三个异步任务都不会执行完成;
如果使用了anyOf方法并行处理这三个异步任务,获得CompletableFuture<Object>对象,但没有使用get()或join()阻塞方法让anyOf方法里面的异步任务执行完成,那么在主线程没有耗时操作的情况下,这三个异步任务都不会执行完成;
如果使用了anyOf方法并行处理这三个异步任务,获得CompletableFuture<Object>对象,而且使用了get()或join()阻塞方法让anyOf方法里面的异步任务执行完成,那么会有一个异步任务执行完成并且CompletableFuture<Object>对象是这个已执行完成的异步任务结果;
如果使用了anyOf方法并行处理这三个异步任务,获得CompletableFuture<Object>对象,而且使用了get()或join()阻塞方法让anyOf方法里面的异步任务执行完成,但也同时使用了各个异步任务的get()方法获取异步任务结果,那么使用anyOf方法就没有意义了;
所以,使用anyOf方法接收多个任意类型的并行异步任务,使用CompletableFuture<Object>对象的get()或join()方法阻塞主线程完成任意一个异步任务,那么CompletableFuture<Object>对象的值就是这个执行完成的异步任务结果的值;

3.4 异步任务异常处理

3.4.1 exceptionally

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("步骤一开始执行...");
        // int i = 1 / 0;
        return "step one";
    }).thenApply(str -> {
        System.out.println("步骤二开始执行...");
        return "step two";
    }).thenApply(str -> {
        System.out.println("步骤三开始执行");
        return 10086;
    }).exceptionally(new Function<Throwable, Integer>() {
        @Override
        public Integer apply(Throwable throwable) {
            System.out.println("错误信息是: " + throwable.getMessage());
            return 201314;
        }
    });
    System.out.println("result is: " + future.get());
}

exceptionally方法及其参数Function定义如下:
CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)
@FunctionalInterface
public interface Function<Throwable, T> {
    T apply(Throwable e)
}
exceptionally方法之前的thenApply方法参数返回值类型是Integer类型,thenApply方法返回值类型是CompletableFuture<Integer>类型,所以exceptionally方法参数Function的第二个泛型类型也是Integer类型,exceptionally方法返回值类型也是CompletableFuture<Integer>类型,这样就可以保证调用链没有异常返回的结果类型和有异常返回的结果类型是一致的,上述案例演示结果如下:
如果调用链方法没有异常,方法调用不会走exceptionally方法
        步骤一开始执行...
        步骤二开始执行...
        步骤三开始执行
        result is: 10086
如果调用链中步骤一方法出现异常,方法调用就不会走后面的方法,直接走exceptionally方法
        步骤一开始执行...
        错误信息是: java.lang.ArithmeticException: / by zero
        result is: 201314
如果调用链中步骤二方法出现异常,方法调用就不会走后面的方法,直接走exceptionally方法
        步骤一开始执行...
        步骤二开始执行...
        错误信息是: java.lang.ArithmeticException: / by zero
        result is: 201314
如果调用链中步骤三方法出现异常,方法调用就不会走后面的方法,直接走exceptionally方法
        步骤一开始执行...
        步骤二开始执行...
        步骤三开始执行
        错误信息是: java.lang.ArithmeticException: / by zero
        result is: 201314

3.4.2 handle

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("步骤一开始执行...");
        // int i = 1 / 0;
        return "step one";
    }).thenApply(str -> {
        System.out.println("步骤二开始执行...");
        return "step two";
    }).thenApply(str -> {
        System.out.println("步骤三开始执行");
        return 10086;
    }).handle(new BiFunction<Integer, Throwable, String>() {
        @Override
        public String apply(Integer integer, Throwable throwable) {
            if (integer != null)
                System.out.println("previous result is: " + integer);
            if (throwable != null)
                System.out.println("error message is: " + throwable.getMessage());
            return "power";
        }
    });
    System.out.println("future result is: " + future.get());
}

handle方法及其参数BiFunction定义如下:
CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)
@FunctionalInterface
public interface BiFunction<T, Throwable, R> {
    R apply(T t, Throwable throwable);
}
无论回调链上的异步任务是否出现异常,handle方法都会执行,如果回调链异步任务正常执行,那么会走handle正常信息处理逻辑,如果回调链异步任务异常执行,那么会走handle的异常信息处理逻辑,还有handle方法返回值类型根据需要指定,上述案例演示结果如下:
如果调用链方法没有异常,方法调用也会走handle方法
        步骤一开始执行...
        步骤二开始执行...
        步骤三开始执行
        previous result is: 10086
        future result is: power
如果调用链中步骤一方法出现异常,方法调用就不会走后面的方法,直接走handle方法
        步骤一开始执行...
        error message is: java.lang.ArithmeticException: / by zero
        future result is: power
如果调用链中步骤二方法出现异常,方法调用就不会走后面的方法,直接走handle方法
        步骤一开始执行...
        步骤二开始执行...
        error message is: java.lang.ArithmeticException: / by zero
        future result is: power
如果调用链中步骤一方法出现异常,方法调用就不会走后面的方法,直接走handle方法
        步骤一开始执行...
        步骤二开始执行...
        步骤三开始执行
        error message is: java.lang.ArithmeticException: / by zero
        future result is: power

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + "异步任务开始执行...");
        return "step one";
    }, executorService).handle((str, err) -> {
        if (str != null)
            System.out.println("result is: " + str);
        if (err != null)
            System.out.println("error msg is:" + err.getMessage());
        System.out.println(printMsg() + "handle方法执行...");
        return "end point";
    });
    future.get();
    executorService.shutdown();
}
public static String printMsg() {
    return FileUtils.currentThread() + "  | "
            + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}

handle方法默认和方法调用者CompletableFuture对象使用同一个线程对象执行异步任务,方法执行结果:
pool-1-thread-1  | 23:52:58异步任务开始执行...
result is: step one
pool-1-thread-1  | 23:52:58handle方法执行...

ForkJoinPool.commonPool-worker-1  | 00:00:49异步任务开始执行...
result is: step one
ForkJoinPool.commonPool-worker-1  | 00:00:49handle方法执行...

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + "异步任务开始执行...");
        return "step one";
    }, executorService).handleAsync((str, err) -> {
        if (str != null)
            System.out.println("result is: " + str);
        if (err != null)
            System.out.println("error msg is:" + err.getMessage());
        System.out.println(printMsg() + "handle方法执行...");
        return "end point";
    });
    future.get();
    executorService.shutdown();
}
public static String printMsg() {
    return FileUtils.currentThread() + "  | "
            + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}

handleAsync(BiFunction<? super T, Throwable, ? extends U> fn)方法在默认线程池中另取一个线程执行异步任务,方法执行结果:
pool-1-thread-1  | 00:02:30异步任务开始执行...
result is: step one
ForkJoinPool.commonPool-worker-1  | 00:02:30handle方法执行...

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + "异步任务开始执行...");
        return "step one";
    }, executorService).handleAsync((str, err) -> {
        if (str != null)
            System.out.println("result is: " + str);
        if (err != null)
            System.out.println("error msg is:" + err.getMessage());
        System.out.println(printMsg() + "handle方法执行...");
        return "end point";
    }, executorService);
    future.get();
    executorService.shutdown();
}
public static String printMsg() {
    return FileUtils.currentThread() + "  | "
            + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}

handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor)方法在自定义线程池中取一个线程执行异步任务,方法执行结果:
pool-1-thread-1  | 00:06:57异步任务开始执行...
result is: step one
pool-1-thread-2  | 00:06:57handle方法执行...

3.4.3 whenComplete

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("步骤一开始执行...");
        // int i = 1 / 0;
        return "step one";
    }).thenApply(str -> {
        System.out.println("步骤二开始执行...");
        return "step two";
    }).thenApply(str -> {
        System.out.println("步骤三开始执行");
        return 10086;
    }).whenComplete(new BiConsumer<Integer, Throwable>() {
        @Override
        public void accept(Integer integer, Throwable throwable) {
            if (integer != null)
                System.out.println("BiConsumer result is: " + integer);
            if (throwable != null)
                System.out.println("throwable is: " + throwable.getMessage());
        }
    });
    System.out.println("future result is: " + future.get());
}

whenComplete方法及其参数BiConsumer定义如下
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action):
@FunctionalInterface
public interface BiConsumer<T, U> {
    void accept(T t, U u);
}
无论回调链上的异步任务是否出现异常,whenComplete方法都会执行,如果回调链异步任务正常执行,那么会走whenComplete正常信息处理逻辑,如果回调链的异步任务异常执行,那么就会走whenComplete的异常信息处理逻辑,上述案例演示结果如下:
如果调用链方法没有异常,方法调用也会走whenComplete方法
        步骤一开始执行...
        步骤二开始执行...
        步骤三开始执行
        BiConsumer result is: 10086
        future result is: 10086
如果调用链中步骤一方法出现异常,方法调用就不会走后面的方法,直接走whenComplete方法
        步骤一开始执行...
        throwable is: java.lang.ArithmeticException: / by zero
如果调用链中步骤二方法出现异常,方法调用就不会走后面的方法,直接走whenComplete​​​​​​​方法
        步骤一开始执行...
        步骤二开始执行...
        throwable is: java.lang.ArithmeticException: / by zero
如果调用链中步骤三方法出现异常,方法调用就不会走后面的方法,直接走whenComplete​​​​​​​方法
        步骤一开始执行...
        步骤二开始执行...
        步骤三开始执行
        throwable is: java.lang.ArithmeticException: / by zero

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + "异步任务开始执行...");
        return "step one";
    }, executorService).whenComplete((str, err) -> {
        if (str != null)
            System.out.println("result is: " + str);
        if (err != null)
            System.out.println("error msg is:" + err.getMessage());
        System.out.println(printMsg() + "whenComplete方法执行...");
    });
    future.get();
    executorService.shutdown();
}
public static String printMsg() {
    return FileUtils.currentThread() + "  | "
            + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}

whenComplete方法默认和方法调用者CompletableFuture对象使用同一个线程对象执行异步任务,方法执行结果:
        pool-1-thread-1  | 19:39:29异步任务开始执行...
        result is: step one
        pool-1-thread-1  | 19:39:29whenComplete方法执行...

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + "异步任务开始执行...");
        return "step one";
    }, executorService).whenCompleteAsync((str, err) -> {
        if (str != null)
            System.out.println("result is: " + str);
        if (err != null)
            System.out.println("error msg is:" + err.getMessage());
        System.out.println(printMsg() + "whenComplete方法执行...");
    });
    future.get();
    executorService.shutdown();
}
public static String printMsg() {
    return FileUtils.currentThread() + "  | "
            + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}

whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action)方法在默认线程池中另取一个线程执行异步任务:
        pool-1-thread-1  | 19:41:59异步任务开始执行...
        result is: step one
        ForkJoinPool.commonPool-worker-1  | 19:41:59whenComplete方法执行...

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println(printMsg() + "异步任务开始执行...");
        return "step one";
    }, executorService).whenCompleteAsync((str, err) -> {
        if (str != null)
            System.out.println("result is: " + str);
        if (err != null)
            System.out.println("error msg is:" + err.getMessage());
        System.out.println(printMsg() + "whenComplete方法执行...");
    }, executorService);
    future.get();
    executorService.shutdown();
}
public static String printMsg() {
    return FileUtils.currentThread() + "  | "
            + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}

whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor)方法在自定义线程池中取一个线程执行异步任务:
        pool-1-thread-1  | 19:44:44异步任务开始执行...
        result is: step one
        pool-1-thread-2  | 19:44:44whenComplete方法执行...

3.5 异步任务的交互

3.5.1 applyToEither

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务一开始执行...");
        System.out.println("任务一睡眠时间是: " + sleep() + "秒");
        return "futureOne result";
    });
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务二开始执行...");
        System.out.println("任务二睡眠时间是: " + sleep() + " 秒");
        return "futureTwo result";
    });
    CompletableFuture<String> futureRes = future1.applyToEither(future2, new Function<String, String>() {
        @Override
        public String apply(String s) {
            System.out.println("最后被执行的任务的结果是: " + s);
            return "任务执行完成";
        }
    });
    System.out.println("futureRes is: " + futureRes.get());
}
public static int sleep() {
    Random random = new Random();
    int time = random.nextInt(10);
    try {
        TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return time;
}

applyToEither方法及其参数定义如下:
public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
future1和future2两个CompletableFuture对象的泛型类型必须是一样的,或是同一类型的子类型,future1和future2其中一个异步任务先执行完成,另一个异步任务也不再执行,直接执行Function函数;
Function函数的apply方法,接收的参数是最先执行完成异步任务,方法返回值类型是根据需求自定义类型,上述案例执行结果:
        任务一开始执行...
        任务二开始执行...
        任务一睡眠时间是: 4秒
        最后被执行的任务的结果是: futureOne result
        futureRes is: 任务执行完成

3.5.2 acceptEither

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务一开始执行...");
        System.out.println("任务一睡眠时间是: " + sleep() + "秒");
        return "futureOne result";
    });
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务二开始执行...");
        System.out.println("任务二睡眠时间是: " + sleep() + " 秒");
        return "futureTwo result";
    });
    CompletableFuture<Void> future = future1.acceptEither(future2, new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println("最后被执行的任务的结果是: " + s);
        }
    });
    future.get();
}
public static int sleep() {
    Random random = new Random();
    int time = random.nextInt(10);
    try {
        TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return time;
}

acceptEither方法及其参数定义如下:
public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
future1和future2两个CompletableFuture对象的泛型类型必须是一样的,或是同一类型的子类型,future1和future2其中一个异步任务先执行完成,另一个异步任务也不再执行,直接执行Consumer函数;
Consumer函数的accept方法,接收的参数是最先执行完成异步任务,方法无返回值,上述案例执行结果:
        任务一开始执行...
        任务二开始执行...
        任务一睡眠时间是: 3秒
        最后被执行的任务的结果是: futureOne result

3.5.3 runAfterEither

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务一开始执行...");
        System.out.println("任务一睡眠时间是: " + sleep() + "秒");
        return "futureOne result";
    });
    CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务二开始执行...");
        System.out.println("任务二睡眠时间是: " + sleep() + " 秒");
        return 100;
    });
    CompletableFuture<Void> future = future1.runAfterEither(future2, new Runnable() {
        @Override
        public void run() {
            System.out.println("异步任务执行完成...");
        }
    });
    future.get();
}
public static int sleep() {
    Random random = new Random();
    int time = random.nextInt(10);
    try {
        TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return time;
}

runAfterEither方法及其参数类型定义如下:
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other, Runnable action)
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
future1和future2两个CompletableFuture对象的泛型类型没要求必须是一样的;
future1和future2其中一个异步任务先执行完成,另一个异步任务也不再执行,直接执行Runnable函数;
Runnable函数的run方法,无参数,仅是接收最先完成异步任务的通知,无返回值,上述案例执行结果:
        任务一开始执行...
        任务二开始执行...
        任务二睡眠时间是: 2 秒
        异步任务执行完成...

3.6 异步任务结果获取

3.6.1 join()

public static void main(String[] args) {
    System.out.println("主线程任务执行 | " + printMsg());
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("异步开始执行...");
        sleep();
        return "future result";
    });
    System.out.println("主线程任务继续执行111 | " + printMsg());
    String futureRes = future.join();
    System.out.println("主线程任务继续执行222 | " + printMsg());
    System.out.println("异步任务执行结果是: " + futureRes);
}
public static int sleep() {
    Random random = new Random();
    int time = random.nextInt(10);
    try {
        TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return time;
}

public static String printMsg() {
    return FileUtils.currentThread() + "  | "
            + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}

join()方法是以阻塞的主线程方式获取异步执行结果,join()方法会抛出运行时异常,在程序中可以不处理,适合流式编程中,上述执行结果:
        主线程任务执行 | main  | 00:26:54
        主线程任务继续执行111 | main  | 00:26:54
        异步开始执行...
        主线程任务继续执行222 | main  | 00:26:59
        异步任务执行结果是: future result

3.6.2 get()

public static void main(String[] args) {
    System.out.println("主线程任务执行 | " + printMsg());
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("异步开始执行...");
        sleep();
        return "future result";
    });
    System.out.println("主线程任务继续执行111 | " + printMsg());
    String futureRes = null;
    try {
        futureRes = future.get();
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    System.out.println("主线程任务继续执行222 | " + printMsg());
    System.out.println("异步任务执行结果是: " + futureRes);
}
public static int sleep() {
    Random random = new Random();
    int time = random.nextInt(10);
    try {
        TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return time;
}

public static String printMsg() {
    return FileUtils.currentThread() + "  | "
            + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}

get()方法是以阻塞的主线程方式获取异步执行结果,get()方法会抛出检查时异常,在程序中需要处理,上述执行结果:
        主线程任务执行 | main  | 00:30:07
        主线程任务继续执行111 | main  | 00:30:07
        异步开始执行...
        主线程任务继续执行222 | main  | 00:30:08
        异步任务执行结果是: future result

3.6.3 get(timeout)

public static void main(String[] args) {
    System.out.println("主线程任务执行 | " + printMsg());
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("异步开始执行...");
        sleep();
        return "future result";
    });
    System.out.println("主线程任务继续执行111 | " + printMsg());
    String futureRes = null;
    try {
        futureRes = future.get(3, TimeUnit.SECONDS);
    } catch (InterruptedException | ExecutionException | TimeoutException e) {
        e.printStackTrace();
    }
    System.out.println("主线程任务继续执行222 | " + printMsg());
    System.out.println("异步任务执行结果是: " + futureRes);
}
public static void sleep() {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
public static String printMsg() {
    return FileUtils.currentThread() + "  | "
            + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}

get(timeout)方法是以阻塞的主线程方式获取异步执行结果,get(timeout)方法会抛出检查时异常,在程序中需要处理;
get(timeout)方法如果在指定的时间内获取到异步执行结果,则程序往下正常执行;
get(timeout)方法如果没有在指定的时间内获取到异步执行结果,则会抛出TimeoutException超时异常,上述执行结果:
        主线程任务执行 | main  | 00:38:19
        主线程任务继续执行111 | main  | 00:38:19
        异步开始执行...
        主线程任务继续执行222 | main  | 00:38:20
        异步任务执行结果是: future result

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值