Java8 CompletableFuture(异步非阻塞)

前言

CompletableFuture 是 java.util.concurrent 库在java 8中新增的主要工具
同传统的Future相比:
1、支持流式计算、函数式编程、完成通知、自定义异常处理等新特性。能够主动设置计算的结果值(主动终结计算过程,即completable),从而在某些场景下主动结束阻塞等待
2、而Future由于不能主动设置计算结果值,一旦调用get()进行阻塞等待,要么当计算结果产生,要么超时,才会返回

supplyAsync(有返回值)和 runAsync(无返回值)

  • 通过supplyAsync创建
@Resource
private ThreadPoolTaskExecutorConfig threadPoolTaskExecutorConfig;
@GetMapping("createWayForSupplyAsync")
public String createWayForSupplyAsync() throws ExecutionException, InterruptedException {
    long startForMaster = System.currentTimeMillis();
    CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(()->{
        try {
            long startForSalve = System.currentTimeMillis();
            Thread.sleep(2000L);
            long endForSalve = System.currentTimeMillis();
            System.out.println(Thread.currentThread().getName() + " 耗时 " + (endForSalve - startForSalve));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "supplyAsync创建CompletableFuture";
    }, threadPoolTaskExecutorConfig.taskExecutorPool());

    long endForMaster = System.currentTimeMillis();
    System.out.println("主线程 " + Thread.currentThread().getName() + " 耗时 " + (endForMaster - startForMaster));
    return completableFuture.get();
}
主线程 http-nio-0.0.0.0-8801-exec-1 耗时 4
自定义异步线程池1 耗时 2013
  • 通过runAsync创建
@GetMapping("createWayForRunAsync")
public void createWayForRunAsync() throws ExecutionException, InterruptedException {
    long startForMaster = System.currentTimeMillis();
    CompletableFuture.runAsync(new Runnable() {
        @Override
        public void run() {
            long startForSalve = System.currentTimeMillis();
            try {
                Thread.sleep(2000L);
                long endForSalve = System.currentTimeMillis();
                System.out.println(Thread.currentThread().getName() + " 耗时 " + (endForSalve - startForSalve));
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }, threadPoolTaskExecutorConfig.taskExecutorPool());

    long endForMaster = System.currentTimeMillis();
    System.out.println("主线程 " + Thread.currentThread().getName() + " 耗时 " + (endForMaster - startForMaster));
}
主线程 http-nio-0.0.0.0-8801-exec-3 耗时 0
自定义异步线程池2 耗时 2003

thenApply / thenAccept / thenRun

thenApply 提交的任务类型需遵从Function签名,也就是有入参和返回值,其中入参为前置任务的结果
thenAccept 提交的任务类型需遵从Consumer签名,也就是有入参但是没有返回值,其中入参为前置任务的结果
thenRun 提交的任务类型需遵从Runnable签名,即没有入参也没有返回值
thenApplyAsync、thenAcceptAsync、thenRunAsync:
带Async后缀的函数表示需要连接的后置任务会被单独提交到线程池中,从而相对前置任务来说是异步运行的
  • thenApply
@GetMapping("then")
public void then() throws ExecutionException, InterruptedException {
   long startForMaster = System.currentTimeMillis();

   CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(() -> {
       System.out.println(MessageFormat.format("completableFuture1 = {0}", Thread.currentThread().getName()));
       return "completableFuture1";
   }, threadPoolTaskExecutorConfig.taskExecutorPool());

   CompletableFuture<String> completableFuture2 = completableFuture1.thenApply((threadName) -> {
       System.out.println(MessageFormat.format("completableFuture2 = {0}", Thread.currentThread().getName()));
       return "completableFuture2";
   });

   long endForMaster = System.currentTimeMillis();
   System.out.println("主线程 " + Thread.currentThread().getName() + " 耗时 " + (endForMaster - startForMaster));
}
主线程 http-nio-0.0.0.0-8801-exec-3 耗时 0
completableFuture1 = 自定义异步线程池2
completableFuture2 = 自定义异步线程池2

thenApply / thenAccept / thenRun 连接的2个任务是有前后依赖的,当且仅当前置任务计算完成时才会开始后置任务的计算

  • thenApplyAsync
@GetMapping("then")
public void then() throws ExecutionException, InterruptedException {
    long startForMaster = System.currentTimeMillis();

    CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(MessageFormat.format("completableFuture1 = {0}", Thread.currentThread().getName()));
        return "completableFuture1";
    }, threadPoolTaskExecutorConfig.taskExecutorPool());

    CompletableFuture<String> completableFuture2 = completableFuture1.thenApplyAsync((threadName) -> {
        System.out.println(MessageFormat.format("completableFuture2 = {0}", Thread.currentThread().getName()));
        return "completableFuture2";
    }, threadPoolTaskExecutorConfig.taskExecutorPool());

    long endForMaster = System.currentTimeMillis();
    System.out.println("主线程 " + Thread.currentThread().getName() + " 耗时 " + (endForMaster - startForMaster));
}
主线程 http-nio-0.0.0.0-8801-exec-4 耗时 0
completableFuture1 = 自定义异步线程池3
completableFuture2 = 自定义异步线程池4

thenCompose

thenCompose适用于两个任务之间有前后依赖关系,但是连接任务又是独立的CompletableFuture

thenComposeAsync:带Async后缀的函数表示需要连接的后置任务会被单独提交到线程池中,从而相对前置任务来说是异步运行的
  • thenCompose
@GetMapping("then")
    public String then() throws ExecutionException, InterruptedException {
        long startForMaster = System.currentTimeMillis();

        CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(MessageFormat.format("completableFuture1 = {0}", Thread.currentThread().getName()));
            return "completableFuture1";
        }, threadPoolTaskExecutorConfig.taskExecutorPool());

        CompletableFuture<String> completableFuture2 = completableFuture1.thenCompose((completableFuture1_r) ->
                CompletableFuture.supplyAsync(() -> {
                    System.out.println(MessageFormat.format("completableFuture2 = {0}", Thread.currentThread().getName()));
                    return completableFuture1_r + ",completableFuture2";
                }, threadPoolTaskExecutorConfig.taskExecutorPool())
        );

        long endForMaster = System.currentTimeMillis();
        System.out.println("主线程 " + Thread.currentThread().getName() + " 耗时 " + (endForMaster - startForMaster));

        return completableFuture2.get();
    }
主线程 http-nio-0.0.0.0-8801-exec-1 耗时 0
completableFuture1 = 自定义异步线程池3
completableFuture2 = 自定义异步线程池4

thenCombine

thenCombineAsync:带Async后缀的函数表示需要连接的后置任务会被单独提交到线程池中,从而相对前置任务来说是异步运行的
  • thenCombine
@GetMapping("then")
public String then() throws ExecutionException, InterruptedException {
    long startForMaster = System.currentTimeMillis();

    CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(MessageFormat.format("completableFuture1 = {0}", Thread.currentThread().getName()));
        return "completableFuture1";
    }, threadPoolTaskExecutorConfig.taskExecutorPool());

    CompletableFuture<String> completableFuture2 = CompletableFuture.supplyAsync(() -> {
        System.out.println(MessageFormat.format("completableFuture2 = {0}", Thread.currentThread().getName()));
        return "completableFuture2";
    }, threadPoolTaskExecutorConfig.taskExecutorPool());

    CompletableFuture<String> completableFuture3 = completableFuture1.thenCombine(completableFuture2, (r1, r2) -> r1 + " " + r2);

    long endForMaster = System.currentTimeMillis();
    System.out.println("主线程 " + Thread.currentThread().getName() + " 耗时 " + (endForMaster - startForMaster));

    return completableFuture3.get();
}
主线程 http-nio-0.0.0.0-8801-exec-2 耗时 0
completableFuture1 = 自定义异步线程池3
completableFuture2 = 自定义异步线程池4

thenCombine连接的两个任务没有依赖关系,前后是并行执行的,只有当两个任务均完成时才会将其结果同时传递给下游处理任务

whenComplete 和 handle

1、whenComplete用于任务完成时的回调通知,解决了传统future在任务完成时无法主动发起通知的问题。前置任务会将计算结果或者抛出的异常作为入参传递给回调通知函数
2、handle与whenComplete的作用类似,handle接收的处理函数有返回值,而且返回值会影响最终获取的计算结果

whenCompleteAsync:带Async后缀的函数表示需要连接的后置任务会被单独提交到线程池中,从而相对前置任务来说是异步运行的
handleAsync:带Async后缀的函数表示需要连接的后置任务会被单独提交到线程池中,从而相对前置任务来说是异步运行的
  • whenComplete
@GetMapping("then")
public String then() throws ExecutionException, InterruptedException {
    long startForMaster = System.currentTimeMillis();

    CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(MessageFormat.format("completableFuture1 = {0}", Thread.currentThread().getName()));
        System.out.println(0/0);
        return "completableFuture1";
    }, threadPoolTaskExecutorConfig.taskExecutorPool());

    CompletableFuture<String> completableFuture2 = completableFuture1.whenComplete((r, e) -> {
        if(e != null){
            System.out.println("操作失败:" + e);
        } else {
            System.out.println("操作成功:" + r);
        }
    });

    long endForMaster = System.currentTimeMillis();
    System.out.println("主线程 " + Thread.currentThread().getName() + " 耗时 " + (endForMaster - startForMaster));

    return completableFuture2.get();
}
主线程 http-nio-0.0.0.0-8801-exec-2 耗时 1
completableFuture1 = 自定义异步线程池2
操作失败:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
  • handle
@GetMapping("then")
public String then() throws ExecutionException, InterruptedException {
    long startForMaster = System.currentTimeMillis();

    CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(MessageFormat.format("completableFuture1 = {0}", Thread.currentThread().getName()));
        System.out.println(0/0);
        return "completableFuture1";
    }, threadPoolTaskExecutorConfig.taskExecutorPool());

    CompletableFuture<String> completableFuture2 = completableFuture1.handle((r, e) -> {
        if(e != null){
            return e.getMessage();
        } else {
            return "completableFuture1";
        }
    });

    long endForMaster = System.currentTimeMillis();
    System.out.println("主线程 " + Thread.currentThread().getName() + " 耗时 " + (endForMaster - startForMaster));

    return completableFuture2.get();
}
主线程 http-nio-0.0.0.0-8801-exec-2 耗时 0
completableFuture1 = 自定义异步线程池2

其它

thenAccepetBoth():两个任务执行完成后,将结果交给thenAccepetBoth处理,无返回值

runAfterBoth():两个任务都执行完成后,执行下一步操作(Runnable类型任务)

applyToEither():两个任务哪个执行的快,就使用哪一个结果,有返回值

acceptEither():两个任务哪个执行的快,就消费哪一个结果,无返回值

runAfterEither():任意一个任务执行完成,进行下一步操作(Runnable类型任务)

allOf():当所有给定的 CompletableFuture 完成时,返回一个新的 CompletableFuture

anyOf():当任何一个给定的CompletablFuture完成时,返回一个新的CompletableFuture

exceptionally:返回一个新的CompletableFuture,当前面的CompletableFuture完成时,它也完成,当它异常完成时,给定函数的异常触发这个CompletableFuture的完成

你可能感兴趣的:(Java,java)