线程池-CompletableFuture 异步编排

线程池-异步编排编笔记-pdf

CompletableFuture 异步编排

一、 需求:当异步任务产生关系与顺序后,怎么办呢?

1).如三个线程ABC,A需要C执行结束才能执行,B随便执行,怎么处理呢?

2).解决方法:CompletableFuture 异步编排

二、业务场景

1.1).场景介绍

查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间
在这里插入图片描述

1.2).业务关系

4、5、6.需要1中的spuId.。复杂,相互关联

三、CompletableFuture使用

1.创建异步对象

1).四个静态方法

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

public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor) 
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor) 
1.1).CompletableFuture 的启动与执行–runAsync(返无回值)、supplyAsync(有返回值)

runAsync

    public static  ExecutorService executor = Executors.newFixedThreadPool(10);
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start");

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("当前线程id " + Thread.currentThread().getId());
            int i = 12 / 2;
            System.out.println("当前线程处理结果 " + i);
        }, executor);
        System.out.println("main...end");
    }

supplyAsync

  public static  ExecutorService executor = Executors.newFixedThreadPool(10);
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程id " + Thread.currentThread().getId());
            int i = 12 / 2;
            System.out.println("当前线程处理结果 " + i);
            return i;
        }, executor);
        Integer integer = future.get();
        System.out.println("future: "+integer);
        System.out.println("main...end");
    }

2.计算完成时回调方法

2.1).完成回调与异常感知whenComplete、exceptionally(方法完成后的感知)

public static  ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> future= CompletableFuture.supplyAsync(() -> {
        System.out.println("当前线程id " + Thread.currentThread().getId());
        int i = 12 / 0;
        System.out.println("当前线程处理结果 " + i);
        return i;
    }, executor).whenComplete((res, exception) -> {
        System.out.println("异步任务完成了。。。结果是: " + res + ",异常时:" + exception);
    }).exceptionally(throwable -> {
        return 10;
    });
   	Integer integer = future.get();
     System.out.println("main...end"+integer);
}
总结:
1).whenComplete、 exceptionally

whenComplete:可以得到异常信息,没法修改返回数据
exceptionally:可以感知异常,同时返回默认 (可以修改返回信息)
whenComplete 可以处理正常和异常的计算结果,exceptionally 处理异常情况。

2).whenComplete 和 whenCompleteAsync 的区别:(是否使用统一线程执行任务)

whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池
来进行执行。
方法不以 Async 结尾,意味着 Action 使用相同的线程执行,而 Async 可能会使用其他线程
执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)

3.handle 方法–处理异常(方法完成后的处理)

在这里插入图片描述

//使用handle处理异常(方法完成后的处理)
public static  ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("当前线程id " + Thread.currentThread().getId());
        int i = 12 / 4;
        System.out.println("当前线程处理结果 " + i);
        return i;
    }, executor).whenComplete((res, exception) -> {
        System.out.println("异步任务完成了。。。结果是: " + res + ",异常时:" + exception);
    }).handle((res,throwable)->{
        if (res!=null){
            return res*2;
        }
        if(throwable!=null) {
            System.out.println("有异常");
        return 0;
        }
        return 0;
    });
    Integer integer = future.get();
    System.out.println("main...end: "+integer);
}
和 complete 一样,可对结果做最后的处理(可处理异常),可改变返回值。 
**handle与handleSync区别**:是否处理结果业务 使用相同线程

4.线程串行化方法-thenApply 、thenAccept 、thenRun

原理;一个任务结束,继续执行其他任务,组成连串任务

在这里插入图片描述

4.1)thenRun:不能获取上一个任务的执行结果

在这里插入图片描述

4.2)thenAccept:可以接受上一步执行结果,但没返回值

在这里插入图片描述

4.3).thenApply:可以接受上一步执行结果,有返回值

在这里插入图片描述

总结:添加Async就是继续执行任务就不是同一线程了

thenApply 方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前
任务的返回值。
thenAccept 方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
thenRun 方法:只要上面的任务执行完成,就开始执行 thenRun,只是处理完任务后,执行thenRun 的后续操作
注意:带有 Async 默认是异步执行的。同之前whenComplete、handle。
以上都要前置任务成功完成。
Function<? super T,? extends U>
T:上一个任务返回结果的类型
U:当前任务的返回值类型

5.两任务组合 - 都要完成thenCombine、thenAcceptBoth、runAfterBoth

在这里插入图片描述

原理:两任务组合 - 都要完成,才执行任务3。

thenCombine:组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值
thenAcceptBoth:组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有
返回值。
runAfterBoth:组合两个 future,不需要获取 future 的结果,只需两个 future 处理完任务后,
处理该任务。

1).创建2个任务(线程)

    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1的线程id: " + Thread.currentThread().getId());
        int i = 10 / 2;
        System.out.println("任务1结束: " + i);
        return i;
    }, executor);
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2 线程id: " + Thread.currentThread().getId());
        System.out.println("任务2结束");
        return "hello";
    }, executor);

2).组合他们(3中方式)

2.1). runAfterBothAsync:不可获取前2个任务结果,无返回值
    future1.runAfterBothAsync(future2,()->{
        System.out.println("任务3开始");
    },executor);
    System.out.println("main...end, ");
2.2).thenAcceptBothAsync:可获取前2个任务结果,但无返回值
    future1.thenAcceptBothAsync(future2, (f1, f2) -> {
        System.out.println("任务3开始, f1= "+f1+ ",f2="+f2);
    }, executor);
    System.out.println("main...end, ");
2.3).thenCombineAsync:可获取前2个任务结果,有返回值
    CompletableFuture<String> future = future1.thenCombineAsync(future2, (f1, f2) -> {
        System.out.println("任务3开始, f1= " + f1 + ",f2=" + f2);
        return f1 + ":" + f2;
    }, executor);
    System.out.println("结果:"+future.get());
    System.out.println("main...end, ");

6.两任务组合 – 一个完成,才执行任务3

在这里插入图片描述

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

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

1).创建2个任务future

2).组合他们(三种方式)

2.1).runAfterEitherAsync-不感知结果,无返回值
    future1.runAfterEitherAsync(future2,()->{
        System.out.println("任务3");
    },executor);
    System.out.println("main...end ");
2.2).acceptEitherAsync-感知上一个任务结果,无返回值
future1.acceptEitherAsync(future2,(res)->{
        System.out.println("任务3,"+res);
    },executor);
    System.out.println("main...end ");
2.3).applyToEitherAsync-感知上一个任务结果, 有返回值
	CompletableFuture<String> future = future1.applyToEitherAsync(future2, (res) -> {
        System.out.println("任务3," + res);
        return res + ":hello";
    }, executor);
    System.out.println("main...end, "+future.get());

7、多任务组合

在这里插入图片描述

1).创建三个future

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

    CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
        System.out.println("查询商品属性信息");
        return "黑色+256G";
    }, executor);
    CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(3000);
            System.out.println("查询商品绝介绍");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "华为P30";
    }, executor);

2).使用

2.1)allOf:等待所有任务完成
    CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
    allOf.get();//等待所有结果都完成(必须加,否则就不能实现等待所有任务完成)
    System.out.println("main...end");
2.2)anyOf:只要有一个任务完成
    CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
    anyOf.get();
    System.out.println("main...end"+anyOf.get());
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值