如何从CompletableFuture获得结果

时间:2015-05-08 14:40:17

标签: java multithreading threadpool executorservice countdownlatch

下面的代码中提到的每个“CompletableFuture.runAsync”都进行了一些计算,我想在每次调用“CompletableFuture.runAsync”时得到结果。换句话说,我希望每个“future0,future1,future2,future3”分别包含每次调用“CompletableFuture.runAsync”的结果

我该怎么做。

*更新

我的要求是,对于每次调用CompletableFuture.runAsync,我都会做一些计算,并且应该返回这些值的ArrayList。在四个calles到CompletableFuture.runAsync之后,我想对返回的ArrayLists进行一些进一步的计算。

    if (this.laplaceImgList != null) {
                        if (!this.laplaceImgList.isEmpty()) {
                            if (this.laplaceImgList.size() == 3) {
                                //executor
                                ExecutorService orintMapExe;
                                CompletableFuture<Void> future0 = null;
                                CompletableFuture<Void> future1 = null;
                                CompletableFuture<Void> future2 = null;
                                CompletableFuture<Void> future3 = null;

                                orintMapExe = Executors.newFixedThreadPool(1);
                                future0 = CompletableFuture.runAsync(new orintMapRun(SysConsts.ORINT_DEG_ZERO , this.laplaceImgList), orintMapExe);
                                future1 = CompletableFuture.runAsync(new orintMapRun(SysConsts.ORINT_DEG_45 , this.laplaceImgList), orintMapExe);
                                future2 = CompletableFuture.runAsync(new orintMapRun(SysConsts.ORINT_DEG_90 , this.laplaceImgList), orintMapExe);
                                future2 = CompletableFuture.runAsync(new orintMapRun(SysConsts.ORINT_DEG_135 , this.laplaceImgList), orintMapExe);
                                CompletableFuture.allOf(future0,future1,future2,future3).join();//blocks the main thread till future0, and future1 finishes

2 个答案:

答案 0 :(得分:4)

我在这里发布一个示例,其中您的作业将返回Future并获得您提供的值列表。正如您所期望的那样(实际列出)它实现了Callable

public class OrintMapRun implements Callable<List<Integer>> {
    final int partOne, partTwo;
    final List<Integer> resultList = new ArrayList<>();
    public OrintMapRun(int partOne, int partTwo) {
        this.partOne = partOne;
        this.partTwo = partTwo;
    }

    @Override
    public List<Integer> call() throws Exception {
        resultList.add(partOne);
        resultList.add(partTwo);
        Thread.sleep(5000); //simulate some computation
        return resultList;
    }
}

现在您需要将这些Callables提交给执行者服务,如下所示:

public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService orintMapExe = Executors.newFixedThreadPool(4);
        List<Future<List<Integer>>> futures = new ArrayList<>();

        futures.add(orintMapExe.submit(new OrintMapRun(10, 10)));
        futures.add(orintMapExe.submit(new OrintMapRun(20, 20)));
        futures.add(orintMapExe.submit(new OrintMapRun(30, 30)));
        futures.add(orintMapExe.submit(new OrintMapRun(40, 40)));

        orintMapExe.shutdown();
        try {
            orintMapExe.awaitTermination(1, TimeUnit.DAYS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        for(Future<List<Integer>> future : futures) {
            List<Integer> result = future.get();
            System.out.println(result);
        }
    }

一旦你得到所有未来的结果,它将是:

[10, 10] [20, 20] [30, 30] [40, 40]

在旁注上,班级名称应始终以大写字母开头。

答案 1 :(得分:0)

除了@i_am_zero的答案之外,您还可以使用CompletionService,它是简单的ExecutorService的包装器。 CompletionService的好处是您始终可以获得最早完成的Future&lt;&gt;对象和后续操作不会被最后完成的任务阻止。根据@ i_am_zero的答案,一个简单的改进如下:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService orintMapExe = Executors.newFixedThreadPool(4);
    CompletionService service = new ExecutorCompletionService(orintMapExe);
    List<Future<List<Integer>>> futures = new ArrayList<>();

    futures.add(orintMapExe.submit(new OrintMapRun(10, 10)));
    futures.add(orintMapExe.submit(new OrintMapRun(20, 20)));
    futures.add(orintMapExe.submit(new OrintMapRun(30, 30)));
    futures.add(orintMapExe.submit(new OrintMapRun(40, 40)));

    for(int i=0; I< futures.size();i++) {
        List<Integer> result = service.take().get();
        System.out.println(result);
    }
}

在大多数情况下,CompletionService应优先于准系ExecutorService,除非您不关心效果。 有一些好的文章解释了诸如https://dzone.com/articles/executorservice-vs之类的好处。

CompletionService对你的问题已经足够了,但是如果你对CompletableFuture感兴趣,我就一个非常适合使用它的场景编写了一个简单的博客:https://medium.com/@zhongzhongzhong/beauty-of-completablefuture-and-where-should-you-use-it-6ac65b7bfbe