知道执行服务何时完成所有提交的任务的最佳方法是什么

时间:2018-09-02 16:19:41

标签: java multithreading executorservice

这是两个选项,请稍稍混淆哪个是最好的选择。

选项1:

ExecutorService es = Executors.newFixedThreadPool(4);
List<Runnable> tasks = getTasks();
CompletableFuture<?>[] futures = tasks.stream()
                               .map(task -> CompletableFuture.runAsync(task, es))
                               .toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();    
es.shutdown();

选项2:

ExecutorService es = Executors.newFixedThreadPool(4);
List< Future<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
    futures.add(es.submit(task));
}

for(Future<?> future : futures) {
    try {
        future.get();
    }catch(Exception e){
        // do logging and nothing else
    }
}
es.shutdown();

在这里放置future.get();尝试捕获是个好主意吧?

3 个答案:

答案 0 :(得分:1)

通过执行以下操作,您可以有效地将每个提交的Future保留在期货列表中:

List< Future<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
    futures.add(es.submit(task));
}

您可以很容易地通过调用Future#isDone方法来检查是否所有提交的作业都刚刚执行完毕,该方法将根据任务是否完成而返回true或false。您可以在相关文档here中查看更多信息。

因此,考虑到以上几点,您可以很好地创建一个简单的帮助程序方法,该方法将迭代期货列表并检查其状态。例如:

private boolean areJobsDone() {
    return futures.stream()
        .allMatch(Future::isDone);
}

请注意,与Future#get方法相反,isDone是非阻塞的(因为它不等待任务返回其结果),因为它可以有效地查询其状态。

使用此方法,您可以继续检查可运行对象的状态,并在继续操作之前先用循环调用该辅助方法来阻塞流。

希望这会有所帮助。

答案 1 :(得分:1)

还有另一种等待所有任务完成的方法。提交所有任务后,请致电

es.shutdown()
es.awaitTermination(Long.MAX_VALUE, TimeUnit.NANO_SECONDS)

Oracle's Java Docs阅读:

  

关闭 [...]启动有序关闭,在该关闭中执行先前提交的任务。

     

awaitTermination [...]阻塞,直到关闭请求后所有任务完成执行,发生超时或当前线程被中断(以先发生者为准)。

关于超时:使用上述值,线程池只会在大约300年后终止。

答案 2 :(得分:0)

类似于Aris_Kortex的提案,

List<CompletableFuture<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
    futures.add(CompletableFuture.runAsync(task, es));
}

,然后创建组合的CompletableFuture:

CompletableFuture<Void> cf = CompletableFuture.allOf(futures.toArray(futires.size()));

然后您可以同步等待所有任务:

cf.get();

与超时同步:

cf.get(1, TimeUnit.SECOND);

异步:

cf.thenRun(()->{finalActions();});