简单的 CompletableFuture学习笔记

简单的 CompletableFuture学习笔记

这里记录一下自己学习的内容,简单记录一下方便后续学习,内容部分参考 CompletableFuture学习博客

1. CompletableFuture简介

在api接口调用时间过长,调用过多外围接口时,为了提升性能,我们采用线程池来负责多线程的处理操作,因为我们需要得到各个子线程处理的结果,所以我们需要使用线程池+Future的方式进行接口优化,但Future在应对并行结果组合以及后续处理等方面显得力不从心,弊端明显,然后便引入了本次学习的CompletableFuture。

CompletableFuture 是 Java 8 中引入的一个新的并发编程工具,它为开发者提供了一种简单、高效的方式来处理异步操作和并发任务。CompletableFuture 可以看作是 Future 的增强版,它提供了更丰富的功能和更方便的使用方式。

2. 简单示例

以下记录一下简单的代码示例

2.1 CompletableFuture初识

当我们需要进行异步处理的时候,我们可以通过CompletableFuture.supplyAsync方法,传入一个具体的要执行的处理逻辑函数,这样就轻松的完成了CompletableFuture的创建与触发执行

方法名称作用描述
supplyAsync静态方法,用于构建一个CompletableFuture<T> 对象,并异步执行传入的参数,允许执行函数有返回值
runAsync静态方法,用于构建一个CompletableFuture<Void> 对象,并异步执行传入函数,与supplyAsync的区别在于此方法传入的是Callable类型,仅执行,没有返回值

示例代码如下:

package cn.git.future;import java.util.concurrent.*;/*** @description: 初始了解completableFuture* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
public class CompletableFutureDemo01 {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {System.out.println("主线程start ......");// 没有返回结果,可以执行任务CompletableFuture.runAsync(() -> {System.out.println("子线程执行了:" + Thread.currentThread().getName());}, executor);// 带返回结果CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {System.out.println("子线程2执行了:" + Thread.currentThread().getName());return 10;}, executor);Integer result = future2.get();System.out.println("result = " + result);System.out.println("主线程end ......");}
}

supplyAsync或者runAsync创建后便会立即执行,无需手动调用触发。

2.2 环环相扣处理

在流水线处理场景中,往往都是一个任务环节处理完成后,下一个任务环节接着上一环节处理结果继续处理。

CompletableFuture用于这种流水线环节驱动类的方法有很多,相互之间主要是在返回值或者给到下一环节的入参上有些许差异,使用时需要注意区分:
在这里插入图片描述
具体的方法的描述归纳如下:

方法名称作用描述
thenApplyCompletableFuture的执行后的结果进行追加处理,并将当前的CompletableFuture泛型对象更改为处理后新的对象类型,返回当前CompletableFuture对象
thenComposethenApply类似,区别点在于:此方法的入参函数返回一个CompletableFuture类型对象
thenAccept在所有异步任务完成后执行一系列操作,与thenApply类似,区别点在于thenApply返回void类型,没有具体结果输出,适合无需返回值的场景
thenRunthenAccept类似,区别点在于thenAccept可以将前面CompletableFuture执行的实际结果作为参数进行传入并使用,但是thenRun方法没有任何入参,只能执行一个Runnable函数,并且返回void类型

在这里插入图片描述
期望总是美好的,但是实际情况却总不尽如人意。在我们编排流水线的时候,如果某一个环节执行抛出异常了,会导致整个流水线后续的环节就没法再继续下去了,这时候需要使用 handle或者whenComplete来处理,具体比较如下

方法名称方法描述
handlethenApply类似,区别点在于handle执行函数的入参有两个,一个是CompletableFuture执行的实际结果,一个是是Throwable对象,这样如果前面执行出现异常的时候,可以通过handle获取到异常并进行处理。
whenComplete与handle类似,区别点在于whenComplete执行后无返回值。
  • whenComplete代码示例:

    package cn.git.future;import java.util.concurrent.*;/*** @description: 回调方法以及发生异常处理*  whenCompleteAsync作用为异步执行*  exceptionally作用为异常处理* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
    public class CompletableFutureDemo02 {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {System.out.println("主线程start ......");// 没有返回结果,可以执行任务CompletableFuture.runAsync(() -> {System.out.println("子线程执行了:" + Thread.currentThread().getName());int i = 10 / 0;}, executor).whenCompleteAsync((res, exec) -> {System.out.println("whenCompleteAsync1");System.out.println("res = " + res);System.out.println("exec = " + exec);}).exceptionally((exec) -> {// 发生异常处理System.out.println("exec1 = " + exec);return null;});// 带返回结果CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {System.out.println("子线程2执行了:" + Thread.currentThread().getName());int i = 10 / 0;return 10;}, executor).whenCompleteAsync((res, exec) -> {System.out.println("whenCompleteAsync2");System.out.println("res = " + res);System.out.println("exec = " + exec);}).exceptionally((exec) -> {// 发生异常处理,带返回值System.out.println("exec2" + exec);return -1;});Integer integer = integerCompletableFuture.get();System.out.println(integer);System.out.println("主线程end ......");executor.shutdown();}
    }

    执行结果
    在这里插入图片描述

  • handle代码示例

    package cn.git.future;import java.util.concurrent.*;/*** @description: handleAsync任务执行后自定义执行器* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
    public class CompletableFutureDemo03 {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {// 没有返回结果,可以执行任务CompletableFuture.runAsync(() -> {System.out.println("子线程执行了:" + Thread.currentThread().getName());}, executor).handleAsync((result, exec) -> {System.out.println("exec = " + exec);return null;});// 带返回结果CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {System.out.println("子线程2执行了:" + Thread.currentThread().getName());int i = 1 / 0;return 10;}, executor).handleAsync((result, exec) -> {System.out.println("exec = " + exec);return 55;});Integer integer = integerCompletableFuture.get();System.out.println(integer);executor.shutdown();}
    }

    执行结果:
    在这里插入图片描述

2.3 多个CompletableFuture组合操作

前面一直在介绍流水线式的处理场景,但是很多时候,流水线处理场景也不会是一个链路顺序往下走的情况,很多时候为了提升并行效率,一些没有依赖的环节我们会让他们同时去执行,然后在某些环节需要依赖的时候,进行结果的依赖合并处理。

CompletableFuture相比于Future的一大优势,就是可以方便的实现多个并行环节的合并处理。相关涉及方法介绍归纳如下:

方法名称方法描述
thenCombine将两个CompletableFuture对象组合起来进行下一步处理,可以拿到两个执行结果,并传给自己的执行函数进行下一步处理,最后返回一个新的CompletableFuture对象。
thenAcceptBoththenCombine类似,区别点在于thenAcceptBoth传入的执行函数没有返回值,即thenAcceptBoth返回值为CompletableFuture<void>
runAfterBoth等待两个CompletableFuture都执行完成后再执行某个Runnable对象,再执行下一个的逻辑,类似thenRun
applyToEither两个CompletableFuture中任意一个完成的时候,继续执行后面给定的新的函数处理。再执行后面给定函数的逻辑,类似thenApply
acceptEither两个CompletableFuture中任意一个完成的时候,继续执行后面给定的新的函数处理。再执行后面给定函数的逻辑,类似thenAccept
runAfterEither等待两个CompletableFuture中任意一个执行完成后再执行某个Runnable对象,可以理解为thenRun的升级版,注意与runAfterBoth对比理解。
allOf静态方法,阻塞等待所有给定的CompletableFuture执行结束后,返回一个CompletableFuture<Void>结果。
anyOf静态方法,阻塞等待任意一个给定的CompletableFuture对象执行结束后,返回一个CompletableFuture<Void>结果。
  • thenAcceptAsync 串行任务编排,任务有先后顺序

    package cn.git.future;import java.util.concurrent.*;/*** @description: 串行任务编排,任务有先后顺序* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
    public class CompletableFutureDemo04 {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {// 没有返回结果,可以执行任务 线程1结束执行线程2CompletableFuture.runAsync(() -> {System.out.println("子线程1执行了:" + Thread.currentThread().getName());}, executor).thenRunAsync(()-> {System.out.println("子线程2执行了:" + Thread.currentThread().getName());}, executor);// 有返回结果,可以执行任务 线程1结束执行线程4CompletableFuture.supplyAsync(() -> {System.out.println("子线程3执行了:" + Thread.currentThread().getName());return 100;}, executor).thenAcceptAsync((param) -> {// 线程3执行结果作为线程4入参参数System.out.println("子线程4执行了:" + Thread.currentThread().getName());System.out.println("线程4参数 = " + param);}, executor);// 有返回结果,获取处理CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {System.out.println("子线程5执行了:" + Thread.currentThread().getName());return 100;}, executor).thenApplyAsync((param) -> {// 线程3执行结果作为线程4入参参数System.out.println("子线程6执行了:" + Thread.currentThread().getName());System.out.println("线程6参数 = " + param);return param * 100;}, executor);System.out.println("thread6 result = " + integerCompletableFuture.get());executor.shutdown();}
    }

    执行结果:在这里插入图片描述

  • runAfterBothAsync两个线程,都完成再执行

    package cn.git.future;import java.util.concurrent.*;/*** @description: 多个线程,都完成再执行* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
    public class CompletableFutureDemo05 {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {// 没有返回结果,串行执行任务final CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {System.out.println("子线程1执行了:" + Thread.currentThread().getName());}, executor).thenRunAsync(() -> {System.out.println("子线程2执行了:" + Thread.currentThread().getName());}, executor);// 串行执行任务CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> {System.out.println("子线程3执行了:" + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return 100;}, executor).thenAcceptAsync((param) -> {// 线程3执行结果作为线程4入参参数System.out.println("子线程4执行了:" + Thread.currentThread().getName());System.out.println("线程4参数 = " + param);}, executor);// 两个任务都执行完成后,执行线程5future1.runAfterBothAsync(future2, () -> {System.out.println("子线程5执行了:" + Thread.currentThread().getName());}, executor);}
    }

    执行结果:
    在这里插入图片描述

  • thenAcceptBothAsync 两个线程都完成再处理带参数

    package cn.git.future;import java.util.concurrent.*;/*** @description: 多个线程,都完成再处理带参数* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
    public class CompletableFutureDemo06 {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {// 没有返回结果,串行执行任务final CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {System.out.println("子线程1执行了:" + Thread.currentThread().getName());}, executor).thenRunAsync(() -> {System.out.println("子线程2执行了:" + Thread.currentThread().getName());}, executor);// 串行执行任务CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {System.out.println("子线程3执行了:" + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return 100;}, executor).exceptionally((e) -> {// 线程3执行结果作为线程4入参参数System.out.println("子线程4执行了:" + Thread.currentThread().getName());System.out.println("子线程4执行异常了:" + e.getMessage());return -1;});// 两个任务都执行完成后,执行线程5,带有返回参数future1.thenAcceptBothAsync(future2, (param1, param2) -> {// param1 = 线程3执行结果, param2 = 线程4执行结果System.out.println("线程5参数1 = " + param1);System.out.println("线程5参数2 = " + param2);System.out.println("子线程5执行了:" + Thread.currentThread().getName());});}
    }

    执行结果:
    在这里插入图片描述

  • thenCombineAsync 两个线程结果进行统一处理,返回新的返回结果

    package cn.git.future;import java.util.concurrent.*;/*** @description: 获取两个线程结果进行统一处理,返回新的返回结果* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
    public class CompletableFutureDemo07 {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {// 没有返回结果,串行执行任务final CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {System.out.println("子线程1执行了:" + Thread.currentThread().getName());return 50;}, executor);// 串行执行任务CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {System.out.println("子线程3执行了:" + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return 100;}, executor).exceptionally((e) -> {// 线程3执行结果作为线程4入参参数System.out.println("子线程4执行了:" + Thread.currentThread().getName());System.out.println("子线程4执行异常了:" + e.getMessage());return -1;});// 获取两个线程结果进行统一处理,返回新的返回结果final CompletableFuture<Integer> future3 = future1.thenCombineAsync(future2, (f1, f2) -> {System.out.println("f1 = " + f1);System.out.println("f2 = " + f2);return f1 + f2;}, executor);System.out.println("future3 = " + future3.get());}
    }

    执行结果:
    在这里插入图片描述

  • runAfterEitherAsync两个任务完成其中任意一个任务

    package cn.git.future;import java.util.concurrent.*;/*** @description: 两个任务完成其中任意一个任务* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
    public class CompletableFutureDemo08 {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {// 没有返回结果,串行执行任务CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {System.out.println("子线程1执行了:" + Thread.currentThread().getName());return 50;}, executor);// 串行执行任务CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("子线程3执行了:" + Thread.currentThread().getName());return 100;}, executor).exceptionally((e) -> {// 线程3执行结果作为线程4入参参数System.out.println("子线程4执行了:" + Thread.currentThread().getName());System.out.println("子线程4执行异常了:" + e.getMessage());return -1;});// 两个任务完成其中任意一个任务,便开始执行future1.runAfterEitherAsync(future2, () -> {System.out.println("子线程5执行了:" + Thread.currentThread().getName());}, executor);}
    }

    执行结果:
    在这里插入图片描述

  • acceptEitherAsync 带有任意一个执行完毕参数信息

    package cn.git.future;import java.util.concurrent.*;/*** @description: 两个任务完成其中任意一个任务* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
    public class CompletableFutureDemo09 {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {// 没有返回结果,串行执行任务CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("子线程1执行了:" + Thread.currentThread().getName());return 50;}, executor);// 串行执行任务CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {System.out.println("子线程3执行了:" + Thread.currentThread().getName());return 100;}, executor).exceptionally((e) -> {// 线程3执行结果作为线程4入参参数System.out.println("子线程4执行了:" + Thread.currentThread().getName());System.out.println("子线程4执行异常了:" + e.getMessage());return -1;});// 两个任务完成其中任意一个任务,便开始执行,带有任意一个执行完毕参数信息future1.acceptEitherAsync(future2, (res) -> {System.out.println("新线程:" + Thread.currentThread().getName());System.out.println("获取任意结果:" + res);}, executor);}
    }

    执行结果:
    在这里插入图片描述

  • applyToEitherAsync 两个任务完成其中任意一个任务,便开始执行,并且获取返回结果

    package cn.git.future;import java.util.concurrent.*;/*** @description: 两个任务完成其中任意一个任务* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
    public class CompletableFutureDemo10 {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {// 没有返回结果,串行执行任务CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("子线程1执行了:" + Thread.currentThread().getName());return 50;}, executor);// 串行执行任务CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {System.out.println("子线程3执行了:" + Thread.currentThread().getName());return 100;}, executor).exceptionally((e) -> {// 线程3执行结果作为线程4入参参数System.out.println("子线程4执行了:" + Thread.currentThread().getName());System.out.println("子线程4执行异常了:" + e.getMessage());return -1;});// 两个任务完成其中任意一个任务,便开始执行,并且获取返回结果final CompletableFuture<Integer> future3 = future1.applyToEitherAsync(future2, (res) -> {System.out.println("子线程2执行了:" + Thread.currentThread().getName());System.out.println("子线程2执行结果:" + res);return res;}, executor);System.out.println("future3 = " + future3.get());}
    }

    执行结果:
    在这里插入图片描述

  • allOf / anyOf 多任务组合处理

    package cn.git.future;import java.util.concurrent.*;/*** @description: 多任务组合处理* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
    public class CompletableFutureDemo11 {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {// 没有返回结果,串行执行任务CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("子线程1执行了:" + Thread.currentThread().getName());return 50;}, executor);// 串行执行任务CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {System.out.println("子线程3执行了:" + Thread.currentThread().getName());return 100;}, executor).exceptionally((e) -> {// 线程3执行结果作为线程4入参参数System.out.println("子线程4执行了:" + Thread.currentThread().getName());System.out.println("子线程4执行异常了:" + e.getMessage());return -1;});// 串行执行任务CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {System.out.println("子线程5执行了:" + Thread.currentThread().getName());return 200;}, executor).exceptionally((e) -> {// 线程3执行结果作为线程4入参参数System.out.println("子线程6执行了:" + Thread.currentThread().getName());System.out.println("子线程6执行异常了:" + e.getMessage());return -1;});// 等待三个任务执行完成 才开始进行后续处理操作,需要進行阻塞操作final CompletableFuture<Void> finalFuture = CompletableFuture.allOf(future1, future2, future3);finalFuture.get();// 任意一个任务执行完成 才开始进行后续处理操作,需要進行阻塞操作final CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2, future3);finalFuture.get();System.out.println("三个任务全部执行完毕啦。。。。。。");}
    }

    执行结果:
    在这里插入图片描述

  • 自定义循环异步调用例子

    package cn.git.future;import cn.git.entity.Person;import java.util.Arrays;
    import java.util.concurrent.*;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;
    import java.util.stream.Stream;/*** @description: 自定义循环异步调用例子* @program: bank-credit-sy* @author: lixuchun* @create: 2024-08-07*/
    public class TestDemo {static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,50,10,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) throws ExecutionException, InterruptedException {// 设定参数信息,循环多少次也是入参参数int [] params = {1,2,3,4,5,6,7,8,9,10};CompletableFuture<Person>[] futures = IntStream.of(params).mapToObj(param -> {CompletableFuture<Person> future = CompletableFuture.supplyAsync(() -> {if (param == 5) {try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("线程:" + Thread.currentThread().getName() + "正在执行任务:" + param);Person person = new Person();person.setSex("男");person.setAge(param);person.setName("张三");return person;}, executor);return future;}).toArray(CompletableFuture[]::new);// 等待所有CompletableFuture完成CompletableFuture.allOf(futures).join();// 获取所有结果Object[] results = Stream.of(futures).map(future -> {try {return future.get();} catch (InterruptedException | ExecutionException e) {e.printStackTrace();return null;}}).toArray();// 打印结果System.out.println(Arrays.stream(results).map(Object::toString).collect(Collectors.joining("\n")));}
    }

    执行结果:
    在这里插入图片描述

2.3 结果等待与获取

在执行线程中将任务放到工作线程中进行处理的时候,执行线程与工作线程之间是异步执行的模式,如果执行线程需要获取到共工作线程的执行结果,则可以通过get或者join方法,阻塞等待并从CompletableFuture中获取对应的值。

对get和join的方法功能含义说明归纳如下:

方法名称作用描述
get()等待CompletableFuture执行完成并获取其具体执行结果,可能会抛出异常,需要代码调用的地方手动try…catch进行处理。
get(long, TimeUnit)get()相同,只是允许设定阻塞等待超时时间,如果等待超过设定时间,则会抛出异常终止阻塞等待。
join()等待CompletableFuture执行完成并获取其具体执行结果,可能会抛出运行时异常,无需代码调用的地方手动try…catch进行处理。

从介绍上可以看出,两者的区别就在于是否需要调用方显式的进行try…catch处理逻辑,使用代码示例如下:

public void testGetAndJoin(String product) {// join无需显式try...catch...PriceResult joinResult = CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouXiXiPrice(product)).join();try {// get显式try...catch...PriceResult getResult = CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouXiXiPrice(product)).get(5L, TimeUnit.SECONDS);} catch (Exception e) {e.printStackTrace();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/394662.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 12系统源码_多屏幕(一)多屏幕设备显示Activity

前言 分屏&#xff1a;是指一个屏幕分出多个窗口&#xff0c;分别显示不同应用的界面&#xff0c;这在当前的手机设备中很常见。多屏&#xff1a;是指一个设备存在多个屏幕&#xff0c;这些可能是虚拟屏幕或者实体硬件屏幕&#xff0c;不同的应用同时显示在不同的屏幕中&#…

SpringBoot多数据源事务处理

多数据源时,一般会配置多个事务管理器 Spring编程式 第二种方式 不可能去同一个方法上写两个事务注解 不允许 SpringBoot 2.6.0之后禁止自己注入自己 本来可以自己注入自己去调用 (为什么要自己注入自己调用,AOP代理,类不是自己写的类) 最简单方式 引入 <dependency&…

【极速前进】20240706-24240714:用于Agent的树搜、理解LLM的语种困惑、事实知识抽取微调、Quiet-STaR

相关博客 【极速前进】20240706-24240714&#xff1a;用于Agent的树搜、理解LLM的语种困惑、事实知识抽取微调、Quiet-STaR 【极速前进】20240615-20240623&#xff1a;Zipper融合模态、VideoLLM视频理解、WebAgent可以自我改善、Nemotron-4、AnyGPT统一模态 【极速前进】20240…

【秋招突围】2024届校招-拼多多笔试题-第一套

🍭 大家好这里是 大厂笔试突围,一起备战秋招笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 编程一对一辅导 ✨ 本系列打算持续跟新 秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🌻 听说本周PDD的笔…

与用户有关的接口

1.获取用户详细信息 跟着黑马程序员继续学习SpringBoot3Vue3 用户登录成功之后跳转到首页&#xff0c;需要获取用户的详细信息 打开接口文档 使用Token令牌解析得到用户名 我们需要根据用户名查询用户&#xff0c;获取详细信息 但是请求参数是无&#xff0c;由于都需要携…

基于微信小程序的小学生口算练习系统

摘 要 随着当今网络的发展&#xff0c;时代的进步&#xff0c;各行各业也在发生着变化&#xff0c;小程序也逐步进入人们的生活&#xff0c;给我们生活或者工作提供了新的方向新的可能。 本毕业设计的内容是设计实现一个小学生口算练习的小程序。微信开发者是以java语言进行…

2023 江苏省第一届数据安全技术应用职业技能竞赛 决赛 部分wp

文章目录 一、前言比赛平台全貌题目附件及工具下载&#xff08;123网盘&#xff09; 二、参考文章三、题目&#xff08;解析&#xff09;一、内存取证-MemoryLife1、请给出内存镜像中黑客使用工具对外连接的IP地址及端口号是___________。&#xff08;格式为IP_PORT&#xff09…

app抓包 burp配置

证书导出 模拟器安装证书 点击安装证书 将证书直接拖进来就行 配置代理 打开浏览器抓包

用python创建极坐标平面

极坐标的介绍 http://t.csdnimg.cn/ucau3http://t.csdnimg.cn/ucau3这个文章里可以知道极坐标的基本知识&#xff0c;接下来实现极坐标的绘制 PolarPlane 是 Manim&#xff08;一个用于数学动画的Python库&#xff09;中的一个类&#xff0c;用于创建极坐标平面。与笛卡尔…

开发android app用于移远模块读写IMEI 模组EC200DEULA-D08-SNNDA 支持socket连接读写IMEI

开放权限 adb kill-serveradb rootadb shell setenforce 0adb install -t app-debug.apkadb shell am start -n com.azhon.spplus/.MainActivity::F310A_WriteIMEI -DWadb.exe forward tcp:5902 tcp:5902pause写读IMEI ADB socket协议 TCP 127.0.0.1:5902 PC与终端APP之间 j…

大放异彩!东软医疗DSA闪耀欧洲

欧洲&#xff0c;作为影像技术的发源地&#xff0c;当下正面临经济发展和人口老龄化的双重考验&#xff0c;对医疗技术的革新与升级需求也愈发迫切。中国高端医疗装备品牌东软医疗&#xff0c;凭借深厚的创新底蕴与对临床需求的精准把握&#xff0c;深耕欧洲市场二十余年&#…

数据结构——排序(2):选择排序+交换排序

目录 一、选择排序 &#xff08;1&#xff09;直接选择排序 ①思路 ②过程图示 ③代码实现 ④代码解释 ⑤优化 1.代码实现 2.过程图示 3.代码解释 4.注意 ⑥直接选择排序的复杂度 &#xff08;2&#xff09;堆排序 ①注意 ②代码实现 二、交换排序 &#xff08…

Vue前端服务加密后端服务解密--AES算法实现

在实际项目中考虑到用户数据的安全性&#xff0c;在用户登录时&#xff0c;前端需要对用户密码加密&#xff08;防止用户密码泄露&#xff09;&#xff0c;服务端收到登录请求时先对密码进行解密&#xff0c;然后再进行用户验证登操作。本文 AES ECB 模式来实现前端机密后端解密…

GPT-5:未来已来,你准备好了吗?

GPT-5 一年半后发布&#xff1f;对此你有何期待&#xff1f; IT之家6月22日消息&#xff0c;在美国达特茅斯工程学院周四公布的采访中&#xff0c;OpenAI首席技术官米拉穆拉蒂被问及GPT-5是否会在明年发布&#xff0c;给出了肯定答案并表示将在一年半后发布。此外&#xff0c;穆…

数据库基础知识

数据库基础知识 主流的数据库连接MySQL理解mysql和mysqld和数据库简单对数据库操作MySQL构架SQL分类存储引擎总结 主流的数据库 SQL Sever&#xff1a; 微软的产品&#xff0c;.Net程序员的最爱&#xff0c;中大型项目。Oracle&#xff1a; 甲骨文产品&#xff0c;适合大型项目…

【Linux网络】网络层协议:IP

本篇博客整理了 TCP/IP 分层模型中网络层的 IP 协议&#xff0c;旨在让读者更加深入理解网络协议栈的设计和网络编程。 目录 一、网络层 二、IP 报头 1&#xff09;报头与有效载荷的分离 2&#xff09;有效载荷的上交 3&#xff09;源 IP 与目的 IP 4&#xff09;生存时间…

学习笔记 韩顺平 零基础30天学会Java(2024.8.7)

P481 Math方法 利用random返回一个[2,7]之间的随机数&#xff1a; 因为random只能返回[0,1)之间的随机数&#xff0c;因此做一下处理&#xff1a;[(int)(a), (int) (aMath.random()*(b-a1))]&#xff0c;对于Math.random()*(b-a1)&#xff0c;其中b-a1&#xff0c;它乘上[0,1)相…

第R3周:天气预测

本文为365天深度学习训练营 中的学习记录博客原作者&#xff1a;K同学啊 任务说明&#xff1a;该数据集提供了来自澳大利亚许多地点的大约 10 年的每日天气观测数据。需要做的是根据这些数据对RainTomorrow进行一个预测&#xff0c;这次任务任务与以往的不同&#xff0c;增加了…

目录函数以及链接文件

一、对stat里面的用户名时间做处理的函数 1.1.getpwuid&#xff08;&#xff09; struct passwd *getpwuid(uid_t uid); 功能: 根据用户id到/etc/passwd文件下解析获得 结构体信息 参数: uid:用户id 返回值: 成功返回id对应用户的信息 失败返回NULL 1. 2.getgrgid&#xf…

数据复盘“黑色星期一”:加密市场震荡,代币表现如何?

8月5日的“黑色星期一”成为了全球金融市场的动荡日&#xff0c;这一波及到加密市场的剧烈震荡导致了大量清算事件和代币的暴跌。本文将通过数据复盘&#xff0c;分析这一事件中加密货币的表现&#xff0c;并探讨未来市场的可能走向。 一、暴跌中的惨痛数据 在“黑色星期一”事…