CompletableFuture异步编排

155 阅读8分钟

前言

由于默认情况下多线程执行任务都是异步的,且线程之间任务执行没有先后顺序,都是哪个线程先抢到任务,哪个线程先执行,所以当一个业务请求需要多线程完成(假如需要 A、B、C 三个线程)且线程AB之间存在前后的依赖关系,而C线程和AB线程无关(例如:A线程启动依赖于B线程的执行返回结果,C线程自个玩) ,所以A和B线程就需要线程编排。来使AB线程执行由原先的并行变为串行;多线程异步编排可以根据线程之间的依赖关系来规划线程之间的执行先后循序。

1、CompletetableFuture介绍

  • CompletableFuture是Java8中提供的Future的扩展功能,简化异步编程的复杂性;
  • 引入函数式编程,通过回调的方式处理计算结果,也提供了转换和组合的方法;
  • 它实现了Future和CompletionStage接口;
  • 借助CompletionStage的方法可以实现链式调用;
  • 一个CompletetableFuture就代表了一个任务,可以用then,when等操作来防止阻塞和轮询isDone的现象出现;
  • 它可能代表一个明确完成的Future,也有可能代表一个完成阶段( CompletionStage ),它支持在计算完成以后触发一些函数或执行某些动作;

2、创建异步对象

CompletableFuture 提供了四个静态方法来创建一个异步操作。

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor);
public static CompletableFuture<Void> runAsync(Runnable runnable);
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor);

1、runXxxx 都是没有返回结果的,supplyXxx 都是可以获取返回结果的

2、可以传入自定义的线程池,否则就用默认的线程池;

源码如下:

/**
 * Returns a new CompletableFuture that is asynchronously completed
 * by a task running in the {@link ForkJoinPool#commonPool()} with
 * the value obtained by calling the given Supplier.
 *
 * @param supplier a function returning the value to be used
 * to complete the returned CompletableFuture
 * @param <U> the function's return type
 * @return the new CompletableFuture
 */
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
    if (supplier == null) throw new NullPointerException();
    CompletableFuture<U> f = new CompletableFuture<U>();
    execAsync(ForkJoinPool.commonPool(), new AsyncSupply<U>(supplier, f));
    return f;
}

/**
 * Returns a new CompletableFuture that is asynchronously completed
 * by a task running in the given executor with the value obtained
 * by calling the given Supplier.
 *
 * @param supplier a function returning the value to be used
 * to complete the returned CompletableFuture
 * @param executor the executor to use for asynchronous execution
 * @param <U> the function's return type
 * @return the new CompletableFuture
 */
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
                                                   Executor executor) {
    if (executor == null || supplier == null)
        throw new NullPointerException();
    CompletableFuture<U> f = new CompletableFuture<U>();
    execAsync(executor, new AsyncSupply<U>(supplier, f));
    return f;
}

/**
 * Returns a new CompletableFuture that is asynchronously completed
 * by a task running in the {@link ForkJoinPool#commonPool()} after
 * it runs the given action.
 *
 * @param runnable the action to run before completing the
 * returned CompletableFuture
 * @return the new CompletableFuture
 */
public static CompletableFuture<Void> runAsync(Runnable runnable) {
    if (runnable == null) throw new NullPointerException();
    CompletableFuture<Void> f = new CompletableFuture<Void>();
    execAsync(ForkJoinPool.commonPool(), new AsyncRun(runnable, f));
    return f;
}

/**
 * Returns a new CompletableFuture that is asynchronously completed
 * by a task running in the given executor after it runs the given
 * action.
 *
 * @param runnable the action to run before completing the
 * returned CompletableFuture
 * @param executor the executor to use for asynchronous execution
 * @return the new CompletableFuture
 */
public static CompletableFuture<Void> runAsync(Runnable runnable,
                                               Executor executor) {
    if (executor == null || runnable == null)
        throw new NullPointerException();
    CompletableFuture<Void> f = new CompletableFuture<Void>();
    execAsync(executor, new AsyncRun(runnable, f));
    return f;
}
public class TestRunAsync {

    // 自定义线程池
    public static final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void test_runAsync() {
        CompletableFuture.runAsync(()->{
            System.out.println("线程开始执行...");
            int i = 100/5;
            System.out.println("运行结果:" + i);    //运行结果:20
        }, executorService);
    }


    public static void test_supplyAsync() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("线程开始执行...");
            int i = 100 / 5;
            System.out.println("运行结果:" + i);    //运行结果:20
            return i;
        }, executorService);
        // 线程执行完毕的返回值
        Integer i = future.get();
        System.out.println("获取到返回值:" + i);    // 获取到返回值:20
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //TestRunAsync.test_supplyAsync();

        TestRunAsync.test_runAsync();
    }


}

3、计算完成时回调方法

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);     
public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn);   

whenComplete 可以处理正常和异常的计算结果,exceptionally 处理异常情况。

whenComplete 和 whenCompleteAsync 的区别:

whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。

whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。

public class CompletableFutureDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        CompletableFuture future = CompletableFuture.supplyAsync(new Supplier<Object>() {
            @Override
            public Object get() {
                System.out.println(Thread.currentThread().getName() + "\t completableFuture");
                //int i = 10 / 0;
                return 1024;
            }
        }).whenComplete(new BiConsumer<Object, Throwable>() {
            @Override
            public void accept(Object o, Throwable throwable) {
                System.out.println("-------o=" + o.toString());
                System.out.println("-------throwable=" + throwable);
            }
        }).exceptionally(new Function<Throwable, Object>() {
            @Override
            public Object apply(Throwable throwable) {
                System.out.println("throwable=" + throwable);
                return 6666;
            }
        });
        System.out.println(future.get());
    }

}

4、hadle方法

public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Executor executor);

和 complete 一样,可对结果做最后的处理(可处理异常),可改变返回值。

public static void test_handle() throws ExecutionException, InterruptedException {

            CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
                System.out.println("线程开始执行...");
                int i = 100 / 20;
                System.out.println("运行结果:" + i);
                return i;
            }, executorService).whenCompleteAsync((result, exception) -> {
                System.out.println("线程执行完毕, 返回结果:" + result +  "异常:" + exception);
                // 线程执行完毕, 返回结果:5异常:null
            }).handle((result, throwable) -> {
                Integer rs = null;
                if (result != null) {
                    rs = result * 2;
                } else if (throwable != null) {
                    rs = 0;
                }
                return rs;
            });
            Integer i = future.get();
            System.out.println("获取到返回值:" + i);    // 获取到返回值:10


    }

5、线程串行化方法

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn);
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn);
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn,Executor executor) ;
public CompletableFuture<Void> thenAccept(Consumer<? super T> action) ;
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) ;
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor) ;
public CompletableFuture<Void> thenRun(Runnable action) ;
public CompletableFuture<Void> thenRunAsync(Runnable action) ;
public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor);

thenRun:只要上一个任务执行完毕,就开始执行thenRun任务;

thenAccept:上一个任务执行完毕后,接收它的返回值,再开始执行thenAccept任务;

thenApply:上一个任务执行完毕后,接收它的返回值,执行thenApplyAsync任务,并返回当前任务的返回值。

public static void test_thenRun() throws ExecutionException, InterruptedException {
       CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
           System.out.println("任务A开始执行...");
           int i = 100 / 20;
           System.out.println("任务A执行完毕, 运行结果:" + i);
           return i;
       }, executorService).thenRun(() -> {
           System.out.println("任务B开始执行...");
       });
   }

   public static void test_thenAccept() throws ExecutionException, InterruptedException {

           CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
               System.out.println("任务A开始执行...");
               int i = 100 / 20;
               System.out.println("任务A执行完毕, 运行结果:" + i);
               return i;
           }, executorService).thenAccept((result) -> {
               System.out.println("任务B开始执行, 接受到任务A的返回结果:" + result);
           });
       

   }

   public static void test_thenApply() throws ExecutionException, InterruptedException {
       CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
           System.out.println("任务A开始执行...");
           int i = 100 / 20;
           System.out.println("任务A执行完毕, 运行结果:" + i);
           return i;
       }, executorService).thenApply((result) -> {
           System.out.println("任务B开始执行, 接受到任务A的返回结果:" + result);
           return 20;
       });
       Integer i = future.get();
       System.out.println("获取到任务B的返回值:" + i);
   }

6、两任务组合–都要完成

public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn) ;
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn) ;
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor) ;
public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action) ;
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action) ;
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action,Executor executor) ;
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,Runnable action);
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action);
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor) ;

两个任务必须都完成,触发该任务。

thenCombine:组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值

thenAcceptBoth:组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有返回值。

runAfterBoth:组合两个 future,不需要获取 future 的结果,只需两个future 处理完任务后,处理该任务。

public static void test_thenCombine() throws ExecutionException, InterruptedException {
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务A开始执行...");
            System.out.println("任务A执行完毕...");
            return "A";
        }, executorService);

        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务B开始执行...");
            System.out.println("任务B执行完毕...");
            return "B";
        }, executorService);

        CompletableFuture<String> futureC = futureA.thenCombine(futureB, (firstResult, secondResult) -> {
            System.out.println("任务C开始执行...");
            System.out.println("接收到任务A的返回值:" + firstResult);
            System.out.println("接收到任务B的返回值:" + secondResult);
            return "C";
        });

        String i = futureC.get();
        System.out.println("获取到任务C的返回值:" + i);
    }

7、两任务组合–一个完成

public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn) ;
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn) ;
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn,Executor executor);
public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action) ;
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action) ;
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action, Executor executor) ;
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,Runnable action) ;
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action) ;
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor) 

当两个任务中,任意一个 future 任务完成的时候,执行任务。

applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。

acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。

runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返回值。

public static void test_applyToEither() throws ExecutionException, InterruptedException {
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务A开始执行...");
            System.out.println("任务A执行完毕...");
            return "A";
        }, executorService);

        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务B开始执行...");
            System.out.println("任务B执行完毕...");
            return "B";
        }, executorService);

        CompletableFuture<String> futureC = futureA.applyToEither(futureB, (result) -> {
            System.out.println("任务C开始执行...");
            System.out.println("接收到执行完毕的任务的返回值:" + result);
            return "C";
        });

        String i = futureC.get();
        System.out.println("获取到任务C的返回值:" + i);

    }

8、多任务组合

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs);
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs);

allOf:等待所有任务完成

anyOf:只要有一个任务完成

public static void test_allOf() throws ExecutionException, InterruptedException {
       CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> {
           System.out.println("任务A开始执行...");
           System.out.println("任务A执行完毕...");
           return "A";
       }, executorService);

       CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
           System.out.println("任务B开始执行...");
           System.out.println("任务B执行完毕...");
           return "B";
       }, executorService);

       CompletableFuture<String> futureC = CompletableFuture.supplyAsync(() -> {
           System.out.println("任务C开始执行...");
           System.out.println("任务C执行完毕...");
           return "C";
       }, executorService);

       // 直到所有任务都执行完毕 才能继续往下执行
       CompletableFuture<Void> allOf = CompletableFuture.allOf(futureA, futureB, futureC);
       allOf.get();

       System.out.println("A:" + futureA.get() + "B:" + futureB.get() + "C:" + futureC.get());
   }

   public static void test_anyOf() throws ExecutionException, InterruptedException {
       CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> {
           System.out.println("任务A开始执行...");
           System.out.println("任务A执行完毕...");
           return "A";
       }, executorService);

       CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
           System.out.println("任务B开始执行...");
           System.out.println("任务B执行完毕...");
           return "B";
       }, executorService);
       
       CompletableFuture<String> futureC = CompletableFuture.supplyAsync(() -> {
           System.out.println("任务C开始执行...");
           try {
               Thread.sleep(3000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println("任务C执行完毕...");
           return "C";
       }, executorService);

       // 有一个任务执行完毕 则继续往下执行
       CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureA, futureB, futureC);
       anyOf.get();
       System.out.println("执行完毕任务的返回值:" + anyOf.get());
   }