CompletableFuture异步编排

目录

一、介绍

二、示例

1. 异步并发,阻塞/异步合并

2. 异步并发,然后消费结果

三、源码解析

1. Future源码

2.  创建CompletableFuture

        2.1. supplyAsync

        2.2. runAsync

        2.3. completedFuture

3. CompletableFuture主要方法

        3.1 thenApply/thenAccept/thenRun

        3.2 thenCombine

        3.3 thenCompose

        3.4 whenComplete

        3.5 handle

4. 总结

        1. 方法总结

        2. 测试源码

四、参考资料


一、介绍

        Future和Callable是JDK5版本,用来获取异步处理结果。通过阻塞或轮询的方式获取结果,如:get()方法阻塞主线程,直至处理完成或超时才能获取结果。阻塞与异步编程的理念相左,同时轮询又耗费CPU资源。

        CompletableFuture是JDK8版本,扩展了Future功能。提供了异步函数式编程,可以通过回调的方式获取处理结果,并且提供了不同异步间的转换和组合(异步编排)。其内部ForkJoinPool实现异步处理,可以把异步回调方式变为同步调用实现。

二、示例

1. 异步并发,阻塞/异步合并

@GetMapping("/testAsync")
@ApiOperation("测试异步调用业")
public Response<List<WcPendantTab>> testAsync(String mgdbId1, String mgdbId2, String mgdbId3){
    // 返回结果
    List<WcPendantTab> result = Lists.newArrayList();
    try {
        // 业务查询
        CompletableFuture<List<WcPendantTab>> future1 = CompletableFuture.supplyAsync(() -> {
            return asyncService.asyncQuery(mgdbId1);
        }, executor);
        CompletableFuture<List<WcPendantTab>> future2 = CompletableFuture.supplyAsync(() -> {
            return asyncService.asyncQuery(mgdbId2);
        }, executor);
        CompletableFuture<List<WcPendantTab>> future3 = CompletableFuture.supplyAsync(() -> {
            return asyncService.asyncQuery(mgdbId3);
        }, executor);

        // 阻塞主线程,合并查询
        CompletableFuture<List<WcPendantTab>> future4  = CompletableFuture
                .allOf(future1, future2, future3)
                // thenApply阻塞主线程;thenApplyAsync不阻塞主线程,异步处理结果
                .thenApply((Void) -> {
                    List<WcPendantTab> merge = Lists.newArrayList();
                    try {
                        merge.addAll(future1.get());
                        merge.addAll(future2.get());
                        merge.addAll(future3.get());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return merge;
                });
        // 获取合并结果
        result.addAll(future4.get());
    } catch (Exception e) {
        e.printStackTrace();
        return Response.error();
    }
    return Response.success(result);
}

        上述代码,查询数据并返回。所以future4使用thenApply来阻塞主线程获取future1、future2、future3的查询结果合并后返回。若是业务需求是不返回响应数据,可以使用thenApplyAsync不阻塞主线程,异步合并处理结果

2. 异步并发,然后消费结果

@GetMapping("/testAsync2")
@ApiOperation("测试异步调用业2")
public Response<List<WcPendantTab>> testAsync2(String mgdbId1, String mgdbId2){
    // 返回结果
    List<WcPendantTab> result = Lists.newArrayList();
    try {
        // 业务查询
        CompletableFuture<List<WcPendantTab>> future1 = CompletableFuture.supplyAsync(() -> {
            return asyncService.asyncQuery(mgdbId1);
        }, executor);
        CompletableFuture<List<WcPendantTab>> future2 = CompletableFuture.supplyAsync(() -> {
            return asyncService.asyncQuery(mgdbId2);
        }, executor);

        // 业务1消费业务2的结果,thenAcceptBoth阻塞主线程;thenAcceptBothAsync,不阻塞主线程
        future1.thenAcceptBoth(future2, new BiConsumer<List<WcPendantTab>, List<WcPendantTab>>() {
            @Override
            public void accept(List<WcPendantTab> wcPendantTabs, List<WcPendantTab> wcPendantTabs2) {
                wcPendantTabs.addAll(wcPendantTabs2);
            }
        });

        // 阻塞主线程,合并查询
        result.addAll(future1.get());
    } catch (Exception e) {
        e.printStackTrace();
        return Response.error();
    }
    return Response.success(result);
}

         上述代码,查询数据并返回。所以future1使用thenAcceptBoth来阻塞主线程获取future1、future2的查询结果,且future1使用future2的数据。若是业务需求是不返回响应数据,可以使用thenAcceptBothAsync不阻塞主线程。

三、源码解析

1. Future源码

package java.util.concurrent;

/**
 * 返回异步计算的结果
 * 检查计算是否完成;等待计算完成;结算完成获取结果
 */
public interface Future<V> {

    // 取消任务的执行
    boolean cancel(boolean mayInterruptIfRunning);

    // 任务完成前,将其取消,返回true
    boolean isCancelled();

    // 任务正常完成,返回true
    boolean isDone();

    // 等待任务执行完成,获取执行结果
    V get() throws InterruptedException, ExecutionException;
    
    // 等待多久后,获取执行结果(正常完成),否则抛出异常
    V get(long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException;
    
}

2.  创建CompletableFuture

        2.1. supplyAsync

异步执行任务并返回处理结果,调用方通过get()或join()获取处理结果。注意:异步执行任务是非阻塞,但是获取结果get()或join()是阻塞方法。有两种方法签名,如下:

// 默认ForkJoinPool线程池执行异步任务
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)

// 指定线程池执行异步任务
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
/**
 * supplyAsync异步执行任务,并返回处理结果
 */
@Test
public void testSupplyAsync(){
    CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
        @Override
        public String get() {
            System.out.println("future.join()");
            return "zyq";
        }
    });
    System.out.println("future.join()2");
    System.out.println(future.join());
}

// 执行结果
future.join()2
future.join()
get result: zyq

        2.2. runAsync

异步执行任务,并没有返回结果。有两种方法签名,如下:

// 默认Fork线程池执行任务,无返回结果
public static CompletableFuture<Void> runAsync(Runnable runnable)

// 指定线程池执行任务,无返回结果
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
/**
 * runAsync异步执行任务,没有处理结果
 */
@Test
public void testRunAsync(){
    CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable() {
        @Override
        public void run() {
            System.out.println("future.join()");
        }
    });
    System.out.println("future.join()2");
    System.out.println("get result: " + future.join());
}

// 执行结果
future.join()2
future.join()
get result: null

        2.3. completedFuture

根据已知结果作为入参,创建一个CompletableFuture。

/**
 * completedFuture:根据已知结果创建一个CompletableFuture
 */
@Test
public void testCompletedFuture(){
    CompletableFuture<String> future = CompletableFuture.completedFuture("zyq");
    System.out.println("future.join()2");
    System.out.println("get result: " + future.join());
}

// 执行结果
future.join()2
get result: zyq

3. CompletableFuture主要方法

同Future相比,CompletableFuture最大的不同是支持流式(Stream)的计算处理,多个任务之间,可以前后相连,从而形成一个计算流。比如:任务1产生的结果,可以直接作为任务2的入参,参与任务2的计算,以此类推。

        3.1 thenApply/thenAccept/thenRun

a. thenApply/thenAccept/thenRun阻塞,区别:提交的任务类型不同
b. thenApplyAsync/thenAcceptAsync/thenRunAsync非阻塞
c. thenApply:Function签名(有入参和返回值),其中入参为前置任务的结果
   thenAccept:Consumer签名(有入参但是没有返回值),其中入参为前置任务的结果
   thenRun:Runnable签名(没有入参也没有返回值)

/**
 * thenApply/thenAccept/thenRun阻塞,区别:提交的任务类型不同
 * 1. thenApplyAsync/thenAcceptAsync/thenRunAsync非阻塞
 * 2. thenApply:Function签名(有入参和返回值),其中入参为前置任务的结果
 *    thenAccept:Consumer签名(有入参但是没有返回值),其中入参为前置任务的结果
 *    thenRun:Runnable签名(没有入参也没有返回值)
 */
@Test
public void testThenApplyAsync(){
    CompletableFuture<Integer> future1 = CompletableFuture.completedFuture(520);

    // future1结果作为future2的入参,Function<入参, 出参>
    CompletableFuture<String> future2 = future1.thenApplyAsync(new Function<Integer, String>() {
        @Override
        public String apply(Integer param) {
            System.out.println("future2.thenApplyAsync(): " + param);
            return param + " zyq";
        }
    });

    System.out.println("testThenApplyAsync()");
    System.out.println("get result: " + future2.join());
}

// 执行结果
testThenApplyAsync()
future2.thenApplyAsync(): 520
get result: 520 zyq

        3.2 thenCombine

thenCombine最大的不同是连接任务可以是一个独立的CompletableFuture,即:允许两个并行任务执行,最后当两个任务均完成时,再将其结果同时传递给下游任务处理。

/**
 * 允许两个并行任务执行,最后当两个任务均完成时,再将其结果同时传递给下游任务处理
 */
@Test
public void testThenCombineAsync(){
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
        @Override
        public Integer get() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("into future1");
            return 520;
        }
    });

    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(new Supplier<String>() {
        @Override
        public String get() {
            System.out.println("into future2");
            return "zyq";
        }
    });

    // future3入参是future1、future2的处理结果
    CompletableFuture<String> future3 = future1.thenCombineAsync(future2, new BiFunction<Integer, String, String>() {
        @Override
        public String apply(Integer f1, String f2) {
            System.out.println("into future3");
            return f1 + " " + f2;
        }
    });

    System.out.println("testThenCombineAsync()");
    System.out.println("get result: " + future3.join());
}

// 执行结果
into future2
testThenCombineAsync()
into future1
into future3
get result: 520 zyq

        3.3 thenCompose

thenCombine主要用于没有前后依赖关系的任务进行连接。那么,如果两个任务之间有前后依赖关系,但是连接任务又是独立的CompletableFuture,则实现内部嵌套

/**
 * CompletableFuture内部嵌入CompletableFuture
 */
@Test
public void testThenComposeAsync(){
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
        @Override
        public Integer get() {
            System.out.println("into future1");
            return 520;
        }
    });

    CompletableFuture<String> future2 = future1.thenComposeAsync(new Function<Integer, CompletableFuture<String>>() {
        @Override
        public CompletableFuture<String> apply(Integer f1) {
            System.out.println("into future2");
            // 内部嵌入CompletableFuture
            return CompletableFuture.supplyAsync(new Supplier<String>() {
                @Override
                public String get() {
                    System.out.println("into future2 into CompletableFuture");
                    return f1 + " " + "zyq";
                }
            });
        }
    });

    System.out.println("testThenComposeAsync()");
    System.out.println("get result: " + future2.join());
}

// 执行结果
testThenComposeAsync()
into future1
into future2
into future2 into CompletableFuture
get result: 520 zyq

        3.4 whenComplete

前置任务完成时的回调通知逻辑,当前任务没有返回值,返回前置任务的结果。注意:解决Future任务完成时,无法主动发起通知的问题。

/**
 * 前置任务完成时的回调通知逻辑。
 * 注意:解决Future任务完成时,无法主动发起通知的问题
 */
@Test
public void testWhenCompleteAsync(){
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
        @Override
        public Integer get() {
            System.out.println("into future1");
            return 520;
        }
    });

    // 返回是future1结果
    // 前置任务完成时的回调通知逻辑
    CompletableFuture<Integer> future2 = future1.whenCompleteAsync(new BiConsumer<Integer, Throwable>() {
        @Override
        public void accept(Integer f1, Throwable throwable) {
            System.out.println("into future2");
            // future1抛出异常
            if (Objects.nonNull(throwable)){
                System.out.println("into future2 is future1 failed");
            }
            // future1正常结果
            else {
                System.out.println("into future2 is future1 " + f1);
            }
        }
    });

    System.out.println("testWhenCompleteAsync()");
    System.out.println("get result: " + future2.join());
}

// 执行结果
into future1
testWhenCompleteAsync()
into future2
into future2 is future1 520
get result: 520

        3.5 handle

与whenComplete类似,但是有返回值,而且返回值会影响最终获取的计算结果

/**
 * 与whenComplete类似,但是有返回值
 */
@Test
public void testHandleAsync(){
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
        @Override
        public Integer get() {
            System.out.println("into future1");
            Long.parseLong("wer");
            return 520;
        }
    });

    // 前置任务完成时的回调通知逻辑,且有返回值
    CompletableFuture<String> future2 = future1.handleAsync(new BiFunction<Integer, Throwable, String>() {
        @Override
        public String apply(Integer f1, Throwable throwable) {
            System.out.println("into future2");
            // future1抛出异常
            if (Objects.nonNull(throwable)){
                System.out.println("into future2 is future1 failed");
                return f1 + " " + "failed";
            }
            // future1正常结果
            else {
                System.out.println("into future2 is future1 " + f1);
                return f1 + " " + "zyq";
            }
        }
    });

    System.out.println("testHandleAsync()");
    System.out.println("get result: " + future2.join());
}

// 执行结果
into future1
testHandleAsync()
into future2
into future2 is future1 failed
get result: null failed

4. 总结

        1. 方法总结

类型方法说明
创建对象supplyAsync静态方法;有返回结果
runAsync静态方法;无返回结果
completedFuture静态方法;已知入参并返回
主要方法

thenApply

/thenApplyAsync

1. 阻塞/非阻塞;

2. Function签名(有入参,有返回值)

thenAccept

/thenAcceptAsync

1. 阻塞/非阻塞;

2. Consumer签名(有入参,没有返回值)

thenRun

/thenRunAsync

1. 阻塞/非阻塞;

2. Runnable签名(没有入参,没有返回值)

thenCombine

/thenCombineAsync

1. 阻塞/非阻塞;

2. 连接任务是独立的CompletableFuture,即:允许两个并行任务执行,再将其结果同时传递给下游任务处理

thenCompose

/thenComposeAsync

1. 阻塞/非阻塞;

2. 没有前后依赖关系的任务进行连接,实现内部嵌套

whenComplete

/whenCompleteAsync

1. 阻塞/非阻塞;

2. 前置任务完成时的回调通知逻辑

3. 当前任务没有返回值,前置任务的结果作为返回值

handle

/handleAsync

1. 阻塞/非阻塞;

2. 前置任务完成时的回调通知逻辑;

3. 当前任务有返回值,影响最终结果

        2. 测试源码

package com.cmmon.instance;

import org.junit.jupiter.api.Test;

import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @description 测试CompletableFuture
 * @author tcm
 * @version 1.0.0
 * @date 2021/12/7 14:32
 **/
public class CompletableFutureTest {

    /**
     * supplyAsync异步执行任务,并返回处理结果
     */
    @Test
    public void testSupplyAsync(){
        CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                System.out.println("future.join()");
                return "zyq";
            }
        });
        System.out.println("future.join()2");
        System.out.println("get result: " + future.join());
    }

    /**
     * runAsync异步执行任务,没有处理结果
     */
    @Test
    public void testRunAsync(){
        CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                System.out.println("future.join()");
            }
        });
        System.out.println("future.join()2");
        System.out.println("get result: " + future.join());
    }

    /**
     * completedFuture:根据已知结果创建一个CompletableFuture
     */
    @Test
    public void testCompletedFuture(){
        CompletableFuture<String> future = CompletableFuture.completedFuture("zyq");
        System.out.println("future.join()2");
        System.out.println("get result: " + future.join());
    }

    /**
     * thenApply/thenAccept/thenRun阻塞,区别:提交的任务类型不同
     * 1. thenApplyAsync/thenAcceptAsync/thenRunAsync非阻塞
     * 2. thenApply:Function签名(有入参和返回值),其中入参为前置任务的结果
     *    thenAccept:Consumer签名(有入参但是没有返回值),其中入参为前置任务的结果
     *    thenRun:Runnable签名(没有入参也没有返回值)
     */
    @Test
    public void testThenApplyAsync(){
        CompletableFuture<Integer> future1 = CompletableFuture.completedFuture(520);

        // future1结果作为future2的入参,Function<入参, 出参>
        CompletableFuture<String> future2 = future1.thenApplyAsync(new Function<Integer, String>() {
            @Override
            public String apply(Integer param) {
                System.out.println("future2.thenApplyAsync(): " + param);
                return param + " zyq";
            }
        });

        System.out.println("testThenApplyAsync()");
        System.out.println("get result: " + future2.join());
    }

    /**
     * 允许两个并行任务执行,最后当两个任务均完成时,再将其结果同时传递给下游任务处理
     */
    @Test
    public void testThenCombineAsync(){
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("into future1");
                return 520;
            }
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                System.out.println("into future2");
                return "zyq";
            }
        });

        // future3入参是future1、future2的处理结果
        CompletableFuture<String> future3 = future1.thenCombineAsync(future2, new BiFunction<Integer, String, String>() {
            @Override
            public String apply(Integer f1, String f2) {
                System.out.println("into future3");
                return f1 + " " + f2;
            }
        });

        System.out.println("testThenCombineAsync()");
        System.out.println("get result: " + future3.join());
    }

    /**
     * CompletableFuture内部嵌入CompletableFuture
     */
    @Test
    public void testThenComposeAsync(){
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                System.out.println("into future1");
                return 520;
            }
        });

        CompletableFuture<String> future2 = future1.thenComposeAsync(new Function<Integer, CompletableFuture<String>>() {
            @Override
            public CompletableFuture<String> apply(Integer f1) {
                System.out.println("into future2");
                // 内部嵌入CompletableFuture
                return CompletableFuture.supplyAsync(new Supplier<String>() {
                    @Override
                    public String get() {
                        System.out.println("into future2 into CompletableFuture");
                        return f1 + " " + "zyq";
                    }
                });
            }
        });

        System.out.println("testThenComposeAsync()");
        System.out.println("get result: " + future2.join());
    }

    /**
     * 前置任务完成时的回调通知逻辑。
     * 注意:解决Future任务完成时,无法主动发起通知的问题
     */
    @Test
    public void testWhenCompleteAsync(){
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                System.out.println("into future1");
                return 520;
            }
        });

        // 返回是future1结果
        // 前置任务完成时的回调通知逻辑
        CompletableFuture<Integer> future2 = future1.whenCompleteAsync(new BiConsumer<Integer, Throwable>() {
            @Override
            public void accept(Integer f1, Throwable throwable) {
                System.out.println("into future2");
                // future1抛出异常
                if (Objects.nonNull(throwable)){
                    System.out.println("into future2 is future1 failed");
                }
                // future1正常结果
                else {
                    System.out.println("into future2 is future1 " + f1);
                }
            }
        });

        System.out.println("testWhenCompleteAsync()");
        System.out.println("get result: " + future2.join());
    }

    /**
     * 与whenComplete类似,但是有返回值
     */
    @Test
    public void testHandleAsync(){
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                System.out.println("into future1");
                Long.parseLong("wer");
                return 520;
            }
        });

        // 前置任务完成时的回调通知逻辑,且有返回值
        CompletableFuture<String> future2 = future1.handleAsync(new BiFunction<Integer, Throwable, String>() {
            @Override
            public String apply(Integer f1, Throwable throwable) {
                System.out.println("into future2");
                // future1抛出异常
                if (Objects.nonNull(throwable)){
                    System.out.println("into future2 is future1 failed");
                    return f1 + " " + "failed";
                }
                // future1正常结果
                else {
                    System.out.println("into future2 is future1 " + f1);
                    return f1 + " " + "zyq";
                }
            }
        });

        System.out.println("testHandleAsync()");
        System.out.println("get result: " + future2.join());
    }

}

四、参考资料

CompletableFuture 详解(一):基本概念及用法_tongtest的博客-CSDN博客_completablefuture 详解

CompletableFuture详解 - 风好大 - 博客园 

Java CompletableFuture 详解 - 毛会懂 - 博客园

Java里面CompletableFuture详解_自我更新-CSDN博客_completablefuture 详解

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值