Bootstrap

java 异步编程 CompletableFuture

理解同步与异步区别

同步:就是在发出一个功能调用时,在没有得到结果之前,将一直处于等待中 即阻塞状态。也就是必须一件一件事做,等前一件做完了才能做下一件事

异步异步通常意味着非阻塞,可以使得我们的任务单独运行在与主线程分离的其他线程中,并且通过回调可以在主线程中得到异步任务的执行状态,是否完成,和是否异常等信息。

CompletableFuture 简介

CompletableFuture 在 Java 里面被用于异步编程,异步通常意味着非阻塞, 可以使得我们的任务单独运行在与主线程分离的其他线程中,并且通过回调可以在主线程中得到异步任务的执行状态,是否完成,和是否异常等信息。
CompletableFuture 实现了 Future, CompletionStage 接口,实现了 Future接口就可以兼容现在有线程池框架,而 CompletionStage 接口才是异步编程 的接口抽象,里面定义多种异步方法,通过这两者集合,从而打造出了强大的 CompletableFuture 类。

Future 与 CompletableFuture

Futrue 在 Java 里面,通常用来表示一个异步任务的引用,比如我们将任务提 交到线程池里面,然后我们会得到一个 Futrue,在 Future 里面有 isDone 方 法来 判断任务是否处理结束,还有 get 方法可以一直阻塞直到任务结束然后获取结果,但整体来说这种方式,还是同步的,因为需要客户端不断阻塞等待或者不断轮询才能知道任务是否完成。

Future 的主要缺点如下:

1)不支持手动完成
我提交了一个任务,但是执行太慢了,我通过其他路径已经获取到了任务结果, 现在没法把这个任务结果通知到正在执行的线程,所以必须主动取消或者一直 等待它执行完成
2)不支持进一步的非阻塞调用
通过 Future 的 get 方法会一直阻塞到任务完成,但是想在获取任务之后执行
额外的任务,因为 Future 不支持回调函数,所以无法实现这个功能
3)不支持链式调用
对于 Future 的执行结果,我们想继续传到下一个 Future 处理使用,从而形成
一个链式的 pipline 调用,这在 Future 中是没法实现的。
4)不支持多个 Future合并
比如我们有 10 个 Future 并行执行,我们想在所有的 Future 运行完毕之后, 执行某些函数,是没法通过 Future 实现的。
5)不支持异常处理
Future 的 API 没有任何的异常处理的 api,所以在异步运行时,如果出了问题 是不好定位的。

CompletableFuture 有 2个 异步方法 

异步调用没有返回值方法 runAsync

异步调用有返回值方法 supplyAsync
 注意  测试时 创建 CompletableFuture  时建议 添加线程池参数  ,如果不添加 默认使用的是 ForkJoinPool.commonPool 的线程池  但是 如果main主线程 结束 整个 任务也将会结束

使用 CompletableFuture

场景:主线程里面创建一个 CompletableFuture,然后主线程调用 get 方法会 阻塞,最后我们在一个子线程中使其终止

    /**
     * 主线程里面创建一个 CompletableFuture,然后主线程调用 get 方法会阻塞,最后我们
     在一个子线程中使其终止
     * @param args
     */
    public static void main(String[] args) throws Exception{
        CompletableFuture<String> future = new CompletableFuture<>();
        new Thread(() -> {
            try{
                System.out.println(Thread.currentThread().getName() + "子线程开始干活");
            //子线程睡 5 秒
                Thread.sleep(5000);
            //在子线程中完成主线程
                future.complete("success");
            }catch (Exception e){
                e.printStackTrace();
            }
        }, "A").start();
        //主线程调用 get 方法阻塞
        System.out.println("主线程调用 get 方法获取结果为: " + future.get());
        System.out.println("主线程完成,阻塞结束!!!!!!");
    }
没有返回值的异步任务

   public static void main(String[] args) throws Exception {
        System.out.println("主线程开始");
        //运行一个没有返回值的异步任务
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -
                > {
        try {
            System.out.println("子线程启动干活");
            Thread.sleep(5000);
            System.out.println("子线程完成");
        } catch (Exception e) {
            e.printStackTrace();
        }
 });
        //主线程阻塞
        future.get();
        System.out.println("主线程结束");
    }
有返回值的异步任务

    /**
     * 有返回值的异步任务
     * @param args
     */
    public static void main(String[] args) throws Exception{
        System.out.println("主线程开始");
        //运行一个有返回值的异步任务
        CompletableFuture<String> future =
                CompletableFuture.supplyAsync(() -> {
                    try {
                        System.out.println("子线程开始任务");
                        Thread.sleep(5000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return "子线程完成了!";
                });
        //主线程阻塞
        String s = future.get();
        System.out.println("主线程结束, 子线程的结果为:" + s);
    }

线程依赖 

当一个线程依赖另一个线程时,可以使用 thenApply 方法来把这两个线程串行化。

 private static Integer num = 10;

    /**
     * 先对一个数加 10,然后取平方
     *
     * @param args
     */
    public static void main(String[] args) throws Exception {
        System.out.println("主线程开始");
        CompletableFuture<Integer> future =
                CompletableFuture.supplyAsync(() -> {
                    try {
                        System.out.println("加 10 任务开始");
                        num += 10;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return num;
                }).thenApply(integer -> {
                    return num * num;
                });
        Integer integer = future.get();
        System.out.println("主线程结束, 子线程的结果为:" + integer);

消费处理结果

thenAccept 消费处理结果, 接收任务的处理结果,并消费处理,无返回结果。  

private static Integer num = 10;

    public static void main(String[] args) throws Exception {
        System.out.println("主线程开始");
        CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("加 10 任务开始");
                num += 10;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return num;
        }).thenApply(integer -> {
            return num * num;
        }).thenAccept(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println("子线程全部处理完成,最后调用了 accept,结果为:" +
                        integer);
            }
        });
    }
异常处理

exceptionally 异常处理,出现异常时触发 

    private static Integer num = 10;

    public static void main(String[] args) throws Exception {
        System.out.println("主线程开始");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 1 / 0;
            System.out.println("加 10 任务开始");
            num += 10;
            return num;
        }).exceptionally(ex -> {
            //异常内容输出
            System.out.println(ex.getMessage());
            return -1;
        });
        System.out.println(future.get());
    }
handle 类似于 thenAccept/thenRun 方法,是最后一步的处理调用,但是同时可以处理异常
private static Integer num = 10;

    public static void main(String[] args) throws Exception {
        System.out.println("主线程开始");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
          //  int i= 1/0;
            System.out.println("加 10 任务开始");
            num += 10;
            return num;
        }).handle((i, ex) -> {
            System.out.println("进入 handle 方法");
            if (ex != null) {
                System.out.println("发生了异常,内容为:" + ex.getMessage());
                return -1;
            } else {
                System.out.println("正常完成,内容为: " + i);
                return i;
            }
        });
        System.out.println(future.get());
    }

结果合并

thenCompose 合并两个有依赖关系的 CompletableFutures 的执行结果
private static Integer num = 10;

    public static void main(String[] args) throws Exception {
        System.out.println("主线程开始");
        //第一步加 10
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("加 10 任务开始");
            num += 10;
            return num;
        });
          //合并
        CompletableFuture<Integer> future1 = future.thenCompose(i ->
        //再来一个 CompletableFuture
                CompletableFuture.supplyAsync(() -> {
                    return i + 1;
                }));
        System.out.println(future.get());
        System.out.println(future1.get());
    }

thenCombine 合并两个没有依赖关系的 CompletableFutures 任务

    private static Integer num = 10;

    public static void main(String[] args) throws Exception {
        System.out.println("主线程开始");
        CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("加 10 任务开始");
            num += 10;
            return num;
        });
        CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("乘以 10 任务开始");
            num = num * 10;
            return num;
        });
        //合并两个结果
        CompletableFuture<Object> future = job1.thenCombine(job2, new
                BiFunction<Integer, Integer, List<Integer>>() {
                    @Override
                    public List<Integer> apply(Integer a, Integer b) {
                        List<Integer> list = new ArrayList<>();
                        list.add(a);
                        list.add(b);
                        return list;
                    }
                });
        System.out.println("合并结果为:" + future.get());
    }
合并多个任务的结果 allOf 与 anyOf
allOf : 一系列独立的 future 任务,等其所有的任务执行完后做一些事情    
  allOf返回的CompletableFuture是多个任务都执行完成后才会执行,只有有一个任务执行异常,则返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回null。
    private static Integer num = 10;

    /**
     * 先对一个数加 10,然后取平方
     * @param args
     */
    public static void main(String[] args) throws Exception{
        System.out.println("主线程开始");
        List<CompletableFuture> list = new ArrayList<>();
        CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("加 10 任务开始");
            num += 10;
            return num;
        });
        list.add(job1);
        CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("乘以 10 任务开始");
            num = num * 10;
            return num;
        });
        list.add(job2);
        CompletableFuture<Integer> job3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("减以 10 任务开始");
            num = num - 10;
            return num;
        });
        list.add(job3);
        CompletableFuture<Integer> job4 = CompletableFuture.supplyAsync(() -> {
            System.out.println("除以 10 任务开始");
            num = num / 10;
            return num;
        });
        list.add(job4);
        //多任务合并
        List<Integer> collect =
                list.stream().map(CompletableFuture<Integer>::join).collect(Collectors.toList());
        System.out.println(collect);
    }

    private static Integer num = 10;

    /**
     * 先对一个数加 10,然后取平方
     * @param args
     */
    public static void main(String[] args) throws Exception{
        System.out.println("主线程开始");
        List<CompletableFuture> list = new ArrayList<>();
        CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("加 10 任务开始");
            num += 10;
            return num;
        });
        list.add(job1);
        CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("乘以 10 任务开始");
            num = num * 10;
            return num;
        });
        list.add(job2);
        CompletableFuture<Integer> job3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("减以 10 任务开始");
            num = num - 10;
            return num;
        });
        list.add(job3);
        CompletableFuture<Integer> job4 = CompletableFuture.supplyAsync(() -> {
            System.out.println("除以 10 任务开始");
            num = num / 10;

            return num;
        });
        list.add(job4);


        CompletableFuture<Void> future = CompletableFuture.allOf(job1, job2, job3, job4).whenComplete((a, b) -> {
            // b为异常对象
            if (b != null) {
                System.out.println("error stack trace->");
                b.printStackTrace();
            } else {
                System.out.println("run succ,result->" + a);
            }
        });

        System.out.println(future.get());

    }

anyOf: 只要在多个 future 里面有一个返回,整个任务就可以结束,而不需要等到每一个
future 结束

    private static Integer num = 10;

    /**
     * 先对一个数加 10,然后取平方
     *
     * @param args
     */
    public static void main(String[] args) throws Exception {
        System.out.println("主线程开始");
        CompletableFuture<Integer>[] futures = new CompletableFuture[4];
        CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {
            try {
                  Thread.sleep(5000);
                System.out.println("加 10 任务开始");
                num += 10;
                return num;
            } catch (Exception e) {
                return 0;
            }
        });
        futures[0] = job1;
        CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {
            try {
                    Thread.sleep(2000);
                System.out.println("乘以 10 任务开始");
                num = num * 10;
                return num;
            } catch (Exception e) {
                return 1;
            }
        });
        futures[1] = job2;
        CompletableFuture<Integer> job3 = CompletableFuture.supplyAsync(() -> {
            try {
                   Thread.sleep(3000);
                System.out.println("减以 10 任务开始");
                num = num  - 10;
                return num;
            } catch (Exception e) {
                return 2;
            }
        });
        futures[2] = job3;
        CompletableFuture<Integer> job4 = CompletableFuture.supplyAsync(() -> {
            try {
                   Thread.sleep(4000);
                System.out.println("除以 10 任务开始");
                num = num / 10;
                return num;
            } catch (Exception e) {
                return 3;
            }
        });
        futures[3] = job4;
        CompletableFuture future = CompletableFuture.anyOf(futures);

        System.out.println(future.get());
    }

①. 获得结果和触发计算(get、getNow、join、complete)

在这里插入图片描述

getNow ()方法  如果计算完成 返回计算完成后的结果  如果调用时没有完成 则返回一个指定的替代值

重点  join  与get 区别 

join方法和get( )方法作用一样,不同的是,join方法不抛出异常

这些不予操作演示

 

②. 对计算结果进行处理(thenApply、handle) 将线程串行化

在这里插入图片描述

①. public <U> CompletableFuture<U> thenApply

计算结果存在依赖关系,这两个线程串行化
由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停

②. public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn):
有异常也可以往下一步走,根据带的异常参数可以进一步处理

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

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

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(1);  } catch (InterruptedException e) {e.printStackTrace();}
            return 1;
        }).thenApply(s->{
            // 这个s 是指上一步的返回值
            System.out.println("-----1");
            //如果加上int error=1/0; 由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫        
             停
            //int error=1/0;
            return s+1;
        }).thenApply(s->{
            System.out.println("-----2");
            return s+2;
        }).whenComplete((v,e)->{
        // v 是指 异步操作数据的返回值  e指上面操作是否出现异常
            if(e==null){
                System.out.println("result-----"+v);
            }
        }).exceptionally(e->{
            e.printStackTrace();
            return null;
        });
        System.out.println(Thread.currentThread().getName()+"\t"+"over....");
        try { TimeUnit.SECONDS.sleep(3);  } catch (InterruptedException e) {e.printStackTrace();}

handle()与thenApply 效果相同 但是  thenApply 出现异常,线程立即停止  而handle 不会出现线程停止问题 会继续执行代码,同时也可以处理异常  等同于 thenApply() 和 exceptionally()结合


            // 创建异步执行任务:
            CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(()->{


                return 1;
            }).thenApply((i)->{

               int q  = 1/0;
                System.out.println("我被处以0了");
                return  i+2;

            }).handle((i,e)->{


                if (e == null){
                    return i +3;
                }else {
                    e.printStackTrace();
                    System.out.println("处理0");
                    return 9;
                }

        });



        try { TimeUnit.SECONDS.sleep(2);  } catch (InterruptedException e) {e.printStackTrace();}
        System.out.println(cf.get());

 ③. 对计算结果进行消费(thenRun、thenAccept、thenApply)

①. thenRun(Runnable runnable)
任务A执行完执行B,并且B不需要A的结果 相当于另起一个线程

②. CompletableFuture<Void> thenAccept(Consumer<? super T> action)
任务A执行完成执行B,B需要A的结果,但是任务B    无返回值

③. public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
任务A执行完成执行B,B需要A的结果,同时任务B    有返回值
 

在这里插入图片描述

这些不予操作演示

某些方法 后缀 有Async 和没有 Async 后缀的方法的区别

带了Async的方法表示的是:会重新在线程池中启动一个线程来执行任务  这个线程池指的是CompletableFuture 创建时的默认线程池 即 ForkJoinPool.commonPool

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)         

④. 对计算速度进行选用(applyToEither、acceptEither、runAfterEither)

①. public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
这个方法表示的是,谁快就用谁的结果

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

applyToEither使用

    CompletableFuture<String> playA = CompletableFuture.supplyAsync(() -> {
            System.out.println("A come in");
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            return "playA";
        });

        CompletableFuture<String> playB = CompletableFuture.supplyAsync(() -> {
            System.out.println("B come in");
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            return "playB";
        });

        CompletableFuture<String> result = playA.applyToEither(playB, f -> {
            return f + " is winer";
        });

        System.out.println(Thread.currentThread().getName()+"\t"+"-----: "+result.join());

---------------------------------------------------------------------------------------------------------------------------


        System.out.println(CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try { TimeUnit.SECONDS.sleep(3);  } catch (InterruptedException e) {e.printStackTrace();}
            return 1;
        }).applyToEither(CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(2);  } catch (InterruptedException e) {e.printStackTrace();}
            return 2;
        }), r -> {
            return r;
        }).join());

runAfterEither 使用

      CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        });



        CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 2;
        });


        CompletableFuture<Void> voidCompletableFuture = integerCompletableFuture.runAfterEither(integerCompletableFuture2, () -> System.out.println(integerCompletableFuture2.join()));


        System.out.println(voidCompletableFuture.join());

带了Async的方法表示的是:会重新在线程池中启动一个线程来执行任务  这个线程池指的是CompletableFuture 创建时的默认线程池 即 ForkJoinPool.commonPool

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)
                                                                                                                        

⑤. 对计算结果进行合并(thenCombine、thenAcceptBoth、runAfterBoth)

①. public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
两个CompletionStage任务都完成后,最终把两个任务的结果一起交给thenCombine来处理
先完成的先等着,等待其他分支任务
 

 thenCombine 使用

有返回值



        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        });

        CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 2;
        });


        CompletableFuture<Integer> future = integerCompletableFuture.thenCombine(integerCompletableFuture2, (a, b) -> a + b);

        System.out.println(future.join());

------------------------------------------------  简化-------------------------------------

  CompletableFuture<Integer>  future = CompletableFuture.supplyAsync(() ->2).thenCombine(CompletableFuture.supplyAsync(() ->1),(a, b) ->a+b);
        System.out.println(future.join());

thenAcceptBoth 使用 无返回值



        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        });

        CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 2;
        });

    CompletableFuture<Void> voidCompletableFuture1 = integerCompletableFuture.thenAcceptBoth(integerCompletableFuture2, (a, b) -> System.out.println(a + b));

------------------------------------------------------ 简化-----------------------------------------------------

   CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> 1).thenAcceptBoth(CompletableFuture.supplyAsync(() -> 2), (a, b) -> System.out.println(a + b));

       System.out.println(voidCompletableFuture.join());

runAfterBoth 使用 无返回值

    CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        });

        CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 2;
        });


        

    CompletableFuture<Void> voidCompletableFuture1 = integerCompletableFuture.runAfterBoth(integerCompletableFuture2, () -> System.out.println(integerCompletableFuture.join()+integerCompletableFuture2.join()));

----------------------------------------- 简化 ---------------------------------------------


        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> 1).runAfterBoth(CompletableFuture.supplyAsync(() -> 2),()-> System.out.println()) ;

thenCompose   合并两个有依赖关系的 CompletableFutures 的执行结果

  thenCompose方法会在某个任务执行完成后,将该任务的执行结果作为方法入参然后执行指定的方法,该方法会返回一个新的CompletableFuture实例,如果该CompletableFuture实例的result不为null,则返回一个基于该result的新的CompletableFuture实例;如果该CompletableFuture实例为null,则,然后执行这个新任务,测试用例如下:


        CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 2;
        });




        CompletableFuture<Integer> future= integerCompletableFuture2.thenCompose(param->{
            System.out.println(param);
        return CompletableFuture.supplyAsync(()-> param+ 2);
        });
        System.out.println( future.join());

---------  简化 -----------------------------------

  CompletableFuture.supplyAsync(() ->2).thenCompose(param ->{

            return CompletableFuture.supplyAsync(()-> param+ 2);

        });

⑥. 多任务组合(allOf、anyOf)

①. allOf:等待所有任务完成
(public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs))

②. anyOf:只要有一个任务完成
(public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs))
 

 CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.jpg";
        });

        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的属性");
            return "黑色+256G";
        });

        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(3);  } catch (InterruptedException e) {e.printStackTrace();}
            System.out.println("查询商品介绍");
            return "华为";
        });
        //需要全部完成
//        futureImg.get();
//        futureAttr.get();
//        futureDesc.get();
        //CompletableFuture<Void> all = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        //all.get();
        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
        anyOf.get();
        System.out.println(anyOf.get());
        System.out.println("main over.....");

同步与异步参考博客

同步与异步的区别(一看则懂)_小柠檬爱编程的博客-CSDN博客_同步异步的区别

Java面试题之:同步与异步?进程与线程?并发与并行?_faramita_of_mine的博客-CSDN博客_同步异步面试题

Java之阻塞和非阻塞以及同步和异步的区别_笑看风云路的博客-CSDN博客_java 异步阻塞

 java 同步和异步_Java中的同步与异步详细介绍_时光派的博客-CSDN博客

 Java --- 线程同步和异步的区别_怪伽先森的博客-CSDN博客_java线程同步和异步的区别

 CompletableFuture 用法参考博客

JUC高并发编程从入门到精通(全)_码农研究僧的博客-CSDN博客_juc并发编程

Juc09_CompletableFuture概述、创建方式、常用API、电商比价需求_所得皆惊喜的博客-CSDN博客_completablefuture.allof

Java8 CompletableFuture 用法全解_孙大圣666的博客-CSDN博客_completablefuture

CompletableFuture详解~allOf_gqltt的博客-CSDN博客_completablefuture.allof

Java8 CompletableFuture(7) CompletableFuture allOf 获取所有线程结果_亚 瑟的博客-CSDN博客_completablefuture.allof

;