CompletableFuture demo

前置知识:函数式接口

Function类

特点:有入参T,有返回值R

@FunctionalInterface
public interface Function<T, R> {
    R apply(T var1);
}

Consumer类

特点:有入参T,无返回值

@FunctionalInterface
public interface Consumer<T> {
    void accept(T var1);
}

Supplier类

特点:无入参,有返回值T

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

Predict类

特点:有入参T,有返回值boolean

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T var1);

总结

在这里插入图片描述

CompletableFuture

在工作中,常常会调用多个服务或者方法去获取不同的数据,如果传统做法就是串行一个个获取,然后封装返回。我们可以尝试使用CompletableFuture,将多个操作交给异步线程执行,然后主线程等待最长任务完成,将所有结果一并返回即可。

1. 创建实例

// 无入参有返回值
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);

我们注意到每种方法都有一个重构的方法。Executor参数可以手动指定线程池,否则默认ForkJoinPool.commonPool()系统级公共线程池。
默认的commonPool的这些线程都是守护线程。我们在编程的时候需要谨慎使用守护线程,如果将我们普通的用户线程设置成守护线程,当我们的程序主线程结束,JVM中不存在其余用户线程,那么CompletableFuture的守护线程会直接退出,造成任务无法完成的问题!!

demo - runAsync不带线程池

主线程执行完毕就结束,无论异步线程任务执行进度

CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
    try {
        Thread.sleep(3000);
        System.out.println("线程[" + Thread.currentThread().getName() + "]异步执行");
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
});
System.out.println("线程[" + Thread.currentThread().getName() + "],结束");

在这里插入图片描述

demo - runAsync带线程池

不需要异步任务执行结果,并且保证异步任务可以正常执行完成

 //解决方案1: 增加抵定义线程池
 CompletableFuture<Void> runWithThreadPool = CompletableFuture.runAsync(() -> {
     try {
         Thread.sleep(3000);
         System.out.println("线程[" + Thread.currentThread().getName() + "]异步执行,自定义线程池");
     } catch (InterruptedException e) {
         throw new RuntimeException(e);
     }
 }, queryBestThreadPool);

 System.out.println("线程[" + Thread.currentThread().getName() + "]结束");

在这里插入图片描述

demo - get()阻塞等待结果

需要异步任务执行结果的场景,变成同步

CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
     try {
         Thread.sleep(3000);
         System.out.println("线程[" + Thread.currentThread().getName() + "]异步执行");
     } catch (InterruptedException e) {
         throw new RuntimeException(e);
     }
 });
 runAsync.get();
 System.out.println("线程[" + Thread.currentThread().getName() + "]结束");

在这里插入图片描述

demo - supplyAsync不带线程池

CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> {
try {
      Thread.sleep(3000);
      System.out.println("线程[" + Thread.currentThread().getName() + "]异步执行");
  } catch (InterruptedException e) {
      throw new RuntimeException(e);
  }
  return "success";
});
//主线程执行完毕,结束
System.out.println("线程[" + Thread.currentThread().getName() + "结束");
CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> {
try {
      Thread.sleep(3000);
      System.out.println("线程[" + Thread.currentThread().getName() + "]异步执行");
  } catch (InterruptedException e) {
      throw new RuntimeException(e);
  }
  return "success";
});
//supplyAsync.get() 会阻塞等待异步任务执行结果,结果返回,主线程打印日志,结束
System.out.println("线程[" + Thread.currentThread().getName() + "],get()="+supplyAsync.get());

demo - supplyAsync带线程池

CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(3000);
        System.out.println("线程[" + Thread.currentThread().getName() + "]异步执行");
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "success";
}, queryBestThreadPool);
//主线程走完,结束
System.out.println("线程[" + Thread.currentThread().getName() + "],结束");
//后续异步线程正常执行完成,打印日志

在这里插入图片描述

CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(3000);
        System.out.println("线程[" + Thread.currentThread().getName() + "]异步执行");
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "success";
}, queryBestThreadPool);
//主线程阻塞等待异步结果,拿到结果后,主线程正常走
System.out.println("线程[" + Thread.currentThread().getName() + "],get()="+supplyAsync.get());

在这里插入图片描述

2. whenComplete

考虑当我们在CompletableFuture执行结束的时候,希望能够得到执行结果、或者异常,然后对结果或者异常做进一步处理。那么我们就需要使用到whenComplete。

CompletableFuture<String> supply = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
   //int a = 1 / 0;
    System.out.println("线程[" + Thread.currentThread().getName() + "],多线程异步执行完成");
    return "success";
    //如果这里不加线程池,主线程任务执行完毕,结束。(不会等异步线程,也不会执行到whenComplete代码里)
}, queryBestThreadPool);

//没有返回
//res:上一步执行结果  ex:上一步抛出的异常
CompletableFuture<String> complete = supply.whenComplete((res, ex) -> {
    if (Objects.nonNull(ex)) {
        ex.printStackTrace();
        System.out.println("失败,线程[" + Thread.currentThread().getName() + "],res: " + res + ",throws:" + ex);
    } else {
        System.out.println("成功,线程[" + Thread.currentThread().getName() + "],res: " + res + ",throws:" + ex);
    }
});
//异常以后,不走下面这行代码,get()抛出的异常,如果异常后,有其他的逻辑需要处理,可以将get() try起来~
System.out.println("线程[" + Thread.currentThread().getName() + "],complete.get():" + complete.get() + ",supply.get():" + supply.get());

正常执行
在这里插入图片描述
异常执行
在这里插入图片描述

3. handle

CompletableFuture<String> supply = CompletableFuture.supplyAsync(() -> {
    // int a = 1 / 0;
    System.out.println("线程[" + Thread.currentThread().getName() + "],多线程异步执行完成");
    return "success";
}, queryBestThreadPool);

CompletableFuture<String> complete = supply.handle((res, ex) -> {
    if (Objects.nonNull(ex)) {
        ex.printStackTrace();
        System.out.println("线程[" + Thread.currentThread().getName() + "],异常,res: " + res + ",throws:" + ex);
        return null;
    } else {
        res = res + "重新组装";
        System.out.println("线程[" + Thread.currentThread().getName() + "],成功,res: " + res);
        return res;
    }
});
//异常后,不走下面
System.out.println("线程[" + Thread.currentThread().getName() + "],结束,supply.get()=" + supply.get() + ",complete.get()=" + complete.get());

正常执行
在这里插入图片描述
异常执行
在这里插入图片描述

4. exceptionally

当发生异常时候的处理,注意异常后返回值类型需要和发生异常的CF返回值类型一致,相当于一种服务降级的思想。

CompletableFuture<String> supply = CompletableFuture.supplyAsync(() -> {
 int a = 1 / 0;
    System.out.println("线程[" + Thread.currentThread().getName() + "],多线程异步执行完成");
    return "success";
}, queryBestThreadPool)
.exceptionally(e -> {
    System.out.println("线程[" + Thread.currentThread().getName() + "],异常,e="+e);
    e.printStackTrace();
    return "error";
});
System.out.println("线程[" + Thread.currentThread().getName() + "],结束,supply.get()=" + supply.get());

正常执行
在这里插入图片描述
异常执行
在这里插入图片描述

5. CompletableFuture组合式Api - allOf

allOf 的返回值是 CompletableFuture类型,这是因为 每个传入的 CompletableFuture 的返回值都可能不同,所以组合的结果是 无法用某种类型来表示的,索性返回 Void 类型。

    static void allof(ThreadPoolTaskExecutor queryBestThreadPool) throws Exception {

        List<Integer> result = new ArrayList<>();

        List<Integer> errorId = new ArrayList<>();
        List<Integer> successId = new ArrayList<>();

        List<CompletableFuture> taskList = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            final Integer temp = i;
            CompletableFuture<Integer> supplyAsyncRes = CompletableFuture.supplyAsync(() -> {
                //处理核心逻辑
                if (temp == 3 || temp == 6 || temp == 9) {
                    int a = 1 / 0;
                }
                System.out.println("线程[" + Thread.currentThread().getName() + "],多线程异步执行完成,i:" + temp);
                return temp;
            }, queryBestThreadPool).whenComplete((res, error) -> {
                if (Objects.nonNull(error)) {
                    errorId.add(temp);
                } else {
                    successId.add(res);
                }
            });
            taskList.add(supplyAsyncRes);
        }

        CompletableFuture.allOf(taskList.toArray(new CompletableFuture[taskList.size()]));
        //阻塞等待任务完成

        for (CompletableFuture cf : taskList) {
            try {
                result.add((Integer) cf.get());
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + "异常啦");
                e.printStackTrace();
            }
        }
        System.out.println("successId:" + successId);
        System.out.println("errorId:" + errorId);

        if (CollectionUtils.isNotEmpty(errorId)) {
            throw new CustomException(CustomExceptionEnum.FAIL);
        }
        //成功后的逻辑
        System.out.println("线程[" + Thread.currentThread().getName() + "],结束,res:" + result);

前置知识来源:https://endwas.cn/blog/78
demo来源:https://blog.csdn.net/qq_40922616/article/details/121045841

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值