异步编程CompletableFuture中多任务组合执行

694 阅读3分钟

这是我参与8月更文挑战的第7天,活动详情查看: 8月更文挑战

有了两个任务并行执行,肯定就会有多个任务的执行,这又涉及到两种情况,

  1. 全部的任务执行完成后在进行后续的操作
  2. 任意一个任务执行完成后就进行后续的操作

针对多任务的组合执行,CompletableFuture只提供了两个方法

 public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
     return andTree(cfs, 0, cfs.length - 1);
 }
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
    return orTree(cfs, 0, cfs.length - 1);
}

看这两个函数的内部调用,都有tree,那应该就用了数这种算法,来让多个任务并行执行。

allOf()使用

当一批任务执行并行执行完成后,然后在执行后面的业务操作,这个时候就可以采用allOf()来实现了,在前面文章中提到的获取文章阅读量、转发量、评论数后在生成报表这种场景就比较适合用allOf()来实现了,好废话不多说,我们一起去看下源码,怎么实现多个任务的 。

allOf()内部调用了andTree(),传递多个任务,看那源码熟悉的算法,二分查找法。内部都是基于二分查找法,将需要执行的任务构建成一个二叉树,然后同时将两个任务添加到栈中执行,作者很巧妙的将多个任务转为了两两任务来执行。 这里有个biRelay()来判断任何合适添加到栈中,等两个任务执行完成后,在继续往下走,继续下一批两个任务

boolean biRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
    Object r, s; Throwable x;
    if (a == null || (r = a.result) == null ||
        b == null || (s = b.result) == null)
        return false;
    if (result == null) {
        if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
            completeThrowable(x, r);
        else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
            completeThrowable(x, s);
        else
            completeNull();
    }
    return true;
}

研究了这么久的CompletableFuture,终于可以将前面写的文章阅读量报表的代码用比较完善的方案来重写一下了。

在最后获取结果的时候,无法判断是那个任务返回的结果,所以一般都执行同类结果,对最后的执行结果进行累加等操作

anyOf()使用

anyOf()和allOf() 类似,只是anyOf任意一个任务任务执行完成后,就会触发后续的操作,可获取到最快那个任务的执行结果,内部的原理也是基于二分查找数来构建二叉树来两两执行任务

到这里CompletableFuture相关的用法都基本上讲解的差不多了,应该可以满足大多数场景了,在这几篇文章中对源码的研究不是很深入,主要是因为我的水平不够,研究不到那么深,反正嘛,这东西能够用就行了,能够满足自己的业务场景,对于源码的研究有兴趣的童鞋自己去研究。个人觉得CompletableFuture也是挺强大,提供的API也比较适用于很多业务场景,能够让我们开箱即用。