CompletableFuture API介绍及使用

1. 介绍

CompletableFuture 是 Java 8 引入的一个用于异步编程的类,位于 java.util.concurrent 包中。它是对 Future 的增强,提供了更强大的功能来支持异步任务的编排、组合和处理。

2. 方法

不使用自定义线程池,会使用ForkJoinPool中的共用线程池CommonPool(CommonPool的大小是CPU核数-1,如果是IO密集的应用,线程数可能成为瓶颈)

2.1 异步执行,不需要结果

使用默认线程池

复制代码
CompletableFuture<Void> future1 = CompletableFuture.runAsync(new Runnable() {
    @Override
    public void run() {
        // 逻辑
    }
});

使用自定义线程池

复制代码
CompletableFuture<Void> future2 = CompletableFuture.runAsync(new Runnable() {
    @Override
    public void run() {
        // 逻辑
    }
}, executor);

2.2 异步执行,需要结果

使用默认线程池

复制代码
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(new Supplier<String>() {
    @Override
    public String get() {
        // 逻辑写在这里
        return "result"; // 结果类型 可以修改T public interface Supplier<T>{}
    }
});

使用自定义线程池

复制代码
CompletableFuture<String> future4 = CompletableFuture.supplyAsync(new Supplier<String>() {
    @Override
    public String get() {
        // 逻辑写在这里
        return "result"; // 结果类型 可以修改T public interface Supplier<T>{}
    }
}, executor);

2.3 thenRun() 同步执行 thenRunAsync() 异步执行

复制代码
CompletableFuture<Void> future5 = future1.thenRun(new Runnable() {
    @Override
    public void run() {
        // 逻辑
    }
});

2.4 thenApply() 同步执行 thenApplyAsync() 异步执行

复制代码
CompletableFuture<String> future6 = future3.thenApply(new Function<String, String>() {
    @Override
    public String apply(String s) {
        return "result";
    }
});

2.5 thenAccept() 同步执行 thenAcceptAsync() 异步执行, 与 thenRun 不同, thenAccept 存在入参

复制代码
CompletableFuture<Void> future7 = future3.thenAccept(new Consumer<String>() {
    @Override
    public void accept(String s) {
        // 逻辑
    }
});

2.6 thenAcceptBoth、thenAcceptBothAsync() 两个 future 全部执行完成,才会执行

复制代码
CompletableFuture<Void> future8 = future3.thenAcceptBoth(future4, new BiConsumer<String, String>() {
    // 获取俩个 future 的结果
    @Override
    public void accept(String s8, String s4) {

    }
});

2.7 applyToEither()、applyToEitherAsync() 两个 future 任意一个执行完成,才会执行

复制代码
CompletableFuture<String> future9 = future3.applyToEither(future4, new Function<String, String>() {
    @Override
    public String apply(String s) {
        return s;
    }
});

2.8 acceptEither 消费 future6 和 future4 的任意一个结果,并消费

复制代码
CompletableFuture<Void> future10 = future6.acceptEither(future4, new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});

2.9 thenCompose()、thenComposeAsync() 新建一个 CompletableFuture,并返回

复制代码
CompletableFuture<String> future11 = future3.thenCompose(new Function<String, CompletableFuture<String>>() {
    @Override
    public CompletableFuture<String> apply(String s) {
        return CompletableFuture.supplyAsync(() -> s + " World");
    }
});

2.10 thenCombine()、thenCombineAsync()

复制代码
CompletableFuture<String> future12 = future3.thenCombine(future4, new BiFunction<String, String, String>() {
    @Override
    public String apply(String s, String s2) {
        return s + s2;
    }
});

2.11 whenComplete()、whenCompleteAsync() 不会吞掉异常

复制代码
CompletableFuture<String> future13 = future3.whenComplete(new BiConsumer<String, Throwable>() {
    @Override
    public void accept(String s, Throwable throwable) {
        System.out.println(s);
    }
});

2.12 handle()、handleAsync() 会吞掉异常

复制代码
CompletableFuture<String> future14 = future3.handle(new BiFunction<String, Throwable, String>() {
    @Override
    public String apply(String s, Throwable throwable) {
        return s;
    }
});

2.13 exceptionally()

复制代码
CompletableFuture<String> future15 = future3.exceptionally(new Function<Throwable, String>() {
    @Override
    public String apply(Throwable throwable) {
        return "error";
    }
});

2.14 allOf()、anyOf()

复制代码
CompletableFuture<Void> future16 = CompletableFuture.allOf(future3, future4); // allOf() 是同步所有任务结果,而不需要进行处理他们的结果
CompletableFuture<Object> future17 = CompletableFuture.anyOf(future3, future4); // anyOf() 是等待其中一个future处理完成,并返回结果

3 使用场景

3.1 例子1

如图所示,各个流程之间有相关依赖,比如执行CF4需要CF1、CF2的结果:

复制代码
        CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> "cf1 result"); // 异步执行有返回值
        CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> "cf2 result");

        CompletableFuture<String> cf3 = cf1.thenApply(s -> "cf3 result");
        CompletableFuture<String> cf4 = cf1.thenCombineAsync(cf2, (s1, s2) -> {
            System.out.println("cf1 result: " + s1);
            System.out.println("cf2 result: " + s2);
            return "cf4 result";
        });
        CompletableFuture<String> cf5 = cf2.thenApply(s -> "cf5 result");

        CompletableFuture<Void> cf6 = CompletableFuture.allOf(cf3, cf4, cf5);
        String cf6Result = cf6.thenApply(v -> {
            cf3.join();
            cf4.join();
            cf5.join();
            return "cf6 result";
        }).get();
        System.out.println(cf6Result);

3.2 例子2

复制代码
ExecutorService executor = Executors.newFixedThreadPool(5);
//1、使用runAsync或supplyAsync发起异步调用
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
  return "result1";
}, executor);

//2、CompletableFuture.completedFuture()直接创建一个已完成状态的CompletableFuture
//使用场景为缓存,命中缓存直接返回
CompletableFuture<String> cf2 = CompletableFuture.completedFuture("result2");

//3、先初始化一个未完成的CompletableFuture,然后通过complete()、completeExceptionally(),完成该CompletableFuture
//使用场景为回调机制、超时处理、任务取消等场景。
CompletableFuture<String> cf2 = new CompletableFuture<>();
cf.complete("success");

4. 问题

合理使用线程池,避免死锁

复制代码
        ExecutorService threadPool1 = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(100));
        CompletableFuture future = CompletableFuture.supplyAsync(() -> {
            return CompletableFuture.supplyAsync(() -> {
                System.out.println("child");
                return "child";
            }, threadPool1).join();// 子任务
        }, threadPool1);
        future.join();
        System.out.println("main");

上面的例子中,当10个线程同事请求时,父类future将10个线程获取,子类不能获取线程导致死锁出现。

5. 总结

函数 使用方式 使用场景
runAsync CompletableFuture.runAsync(Runnable task) 异步执行一个无返回值的任务。
runAsync CompletableFuture.runAsync(Runnable task, Executor executor) 异步执行一个无返回值的任务,使用自定义线程池。
supplyAsync CompletableFuture.supplyAsync(Supplier<T> supplier) 异步执行一个有返回值的任务。
supplyAsync CompletableFuture.supplyAsync(Supplier<T> supplier, Executor executor) 异步执行一个有返回值的任务,使用自定义线程池。
thenRun future.thenRun(Runnable action) 在前一个任务完成后,同步执行一个无返回值的操作。
thenRunAsync future.thenRunAsync(Runnable action) 在前一个任务完成后,异步执行一个无返回值的操作。
thenApply future.thenApply(Function<T, U> fn) 在前一个任务完成后,同步处理其结果并返回新值。
thenApplyAsync future.thenApplyAsync(Function<T, U> fn) 在前一个任务完成后,异步处理其结果并返回新值。
thenAccept future.thenAccept(Consumer<T> action) 在前一个任务完成后,同步消费其结果(无返回值)。
thenAcceptAsync future.thenAcceptAsync(Consumer<T> action) 在前一个任务完成后,异步消费其结果(无返回值)。
thenAcceptBoth future1.thenAcceptBoth(future2, BiConsumer<T, U> action) 在两个任务都完成后,同步消费它们的结果(无返回值)。
thenAcceptBothAsync future1.thenAcceptBothAsync(future2, BiConsumer<T, U> action) 在两个任务都完成后,异步消费它们的结果(无返回值)。
applyToEither future1.applyToEither(future2, Function<T, U> fn) 在两个任务中任意一个完成后,同步处理其结果并返回新值。
applyToEitherAsync future1.applyToEitherAsync(future2, Function<T, U> fn) 在两个任务中任意一个完成后,异步处理其结果并返回新值。
acceptEither future1.acceptEither(future2, Consumer<T> action) 在两个任务中任意一个完成后,同步消费其结果(无返回值)。
acceptEitherAsync future1.acceptEitherAsync(future2, Consumer<T> action) 在两个任务中任意一个完成后,异步消费其结果(无返回值)。
thenCompose future.thenCompose(Function<T, CompletableFuture<U>> fn) 在前一个任务完成后,同步启动一个新的 CompletableFuture
thenComposeAsync future.thenComposeAsync(Function<T, CompletableFuture<U>> fn) 在前一个任务完成后,异步启动一个新的 CompletableFuture
thenCombine future1.thenCombine(future2, BiFunction<T, U, V> fn) 在两个任务都完成后,同步处理它们的结果并返回新值。
thenCombineAsync future1.thenCombineAsync(future2, BiFunction<T, U, V> fn) 在两个任务都完成后,异步处理它们的结果并返回新值。
whenComplete future.whenComplete(BiConsumer<T, Throwable> action) 在前一个任务完成后,同步处理其结果或异常(不改变结果或异常)。
whenCompleteAsync future.whenCompleteAsync(BiConsumer<T, Throwable> action) 在前一个任务完成后,异步处理其结果或异常(不改变结果或异常)。
handle future.handle(BiFunction<T, Throwable, U> fn) 在前一个任务完成后,同步处理其结果或异常,并返回新值(可覆盖异常)。
handleAsync future.handleAsync(BiFunction<T, Throwable, U> fn) 在前一个任务完成后,异步处理其结果或异常,并返回新值(可覆盖异常)。
exceptionally future.exceptionally(Function<Throwable, T> fn) 在前一个任务失败时,同步处理异常并返回备用值。
allOf CompletableFuture.allOf(future1, future2, ...) 等待所有任务完成(无返回值)。
anyOf CompletableFuture.anyOf(future1, future2, ...) 等待任意一个任务完成,并返回其结果(返回 Object 类型)。

附录

美团工具类 : CompletableFuture原理与实践-外卖商家端API的异步化

复制代码
import lombok.extern.slf4j.Slf4j;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.BinaryOperator;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * CompletableFuture封装工具类
 */
@Slf4j
public class FutureUtils {

    /**
     * 设置CF状态为失败
     */
    public static <T> CompletableFuture<T> failed(Throwable ex) {
        CompletableFuture<T> completableFuture = new CompletableFuture<>();
        completableFuture.completeExceptionally(ex);
        return completableFuture;
    }

    /**
     * 设置CF状态为成功
     */
    public static <T> CompletableFuture<T> success(T result) {
        CompletableFuture<T> completableFuture = new CompletableFuture<>();
        completableFuture.complete(result);
        return completableFuture;
    }

    /**
     * 将List<CompletableFuture<T>> 转为 CompletableFuture<List<T>>
     */
    public static <T> CompletableFuture<List<T>> sequence(Collection<CompletableFuture<T>> completableFutures) {
        return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
                .thenApply(v -> completableFutures.stream()
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList())
                );
    }

    /**
     * 将List<CompletableFuture<List<T>>> 转为 CompletableFuture<List<T>>
     * 多用于分页查询的场景
     */
    public static <T> CompletableFuture<List<T>> sequenceList(Collection<CompletableFuture<List<T>>> completableFutures) {
        return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
                .thenApply(v -> completableFutures.stream()
                        .flatMap(listFuture -> listFuture.join().stream())
                        .collect(Collectors.toList())
                );
    }

    /*
     * 将List<CompletableFuture<Map<K, V>>> 转为 CompletableFuture<Map<K, V>>
     * @Param mergeFunction 自定义key冲突时的merge策略
     */
    public static <K, V> CompletableFuture<Map<K, V>> sequenceMap(
            Collection<CompletableFuture<Map<K, V>>> completableFutures, BinaryOperator<V> mergeFunction) {
        return CompletableFuture
                .allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
                .thenApply(v -> completableFutures.stream().map(CompletableFuture::join)
                        .flatMap(map -> map.entrySet().stream())
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, mergeFunction)));
    }

    /**
     * 将List<CompletableFuture<T>> 转为 CompletableFuture<List<T>>,并过滤调null值
     */
    public static <T> CompletableFuture<List<T>> sequenceNonNull(Collection<CompletableFuture<T>> completableFutures) {
        return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
                .thenApply(v -> completableFutures.stream()
                        .map(CompletableFuture::join)
                        .filter(e -> e != null)
                        .collect(Collectors.toList())
                );
    }

    /**
     * 将List<CompletableFuture<List<T>>> 转为 CompletableFuture<List<T>>,并过滤调null值
     * 多用于分页查询的场景
     */
    public static <T> CompletableFuture<List<T>> sequenceListNonNull(Collection<CompletableFuture<List<T>>> completableFutures) {
        return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
                .thenApply(v -> completableFutures.stream()
                        .flatMap(listFuture -> listFuture.join().stream().filter(e -> e != null))
                        .collect(Collectors.toList())
                );
    }

    /**
     * 将List<CompletableFuture<Map<K, V>>> 转为 CompletableFuture<Map<K, V>>
     *
     * @Param filterFunction 自定义过滤策略
     */
    public static <T> CompletableFuture<List<T>> sequence(Collection<CompletableFuture<T>> completableFutures,
                                                          Predicate<? super T> filterFunction) {
        return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
                .thenApply(v -> completableFutures.stream()
                        .map(CompletableFuture::join)
                        .filter(filterFunction)
                        .collect(Collectors.toList())
                );
    }

    /**
     * 将List<CompletableFuture<List<T>>> 转为 CompletableFuture<List<T>>
     *
     * @Param filterFunction 自定义过滤策略
     */
    public static <T> CompletableFuture<List<T>> sequenceList(Collection<CompletableFuture<List<T>>> completableFutures,
                                                              Predicate<? super T> filterFunction) {
        return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
                .thenApply(v -> completableFutures.stream()
                        .flatMap(listFuture -> listFuture.join().stream().filter(filterFunction))
                        .collect(Collectors.toList())
                );
    }

    /**
     * 将CompletableFuture<Map<K,V>>的list转为 CompletableFuture<Map<K,V>>。 多个map合并为一个map。 如果key冲突,采用新的value覆盖。
     */
    public static <K, V> CompletableFuture<Map<K, V>> sequenceMap(
            Collection<CompletableFuture<Map<K, V>>> completableFutures) {
        return CompletableFuture
                .allOf(completableFutures.toArray(new CompletableFuture<?>[0]))
                .thenApply(v -> completableFutures.stream().map(CompletableFuture::join)
                        .flatMap(map -> map.entrySet().stream())
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> b)));
    }
}