一尘不染

JavaExecutorService,如何等待所有任务完成

java

等待所有任务ExecutorService完成的最简单方法是什么?我的任务主要是计算,所以我只想运行大量的作业-每个内核上一个。现在,我的设置如下所示:

ExecutorService es = Executors.newFixedThreadPool(2);
for (DataTable singleTable : uniquePhrases) {   
    es.execute(new ComputeDTask(singleTable));
}
try{
    es.wait();
} 
catch (InterruptedException e){
    e.printStackTrace();
}

ComputeDTask实现可运行。这似乎是正确执行的任务,但代码崩溃上wait()IllegalMonitorStateException。这很奇怪,因为我玩了一些玩具示例,而且看起来很奏效。

uniquePhrases包含数以万计的元素。我应该使用其他方法吗?我正在寻找尽可能简单的东西


阅读 1092

收藏
2020-03-05

共1个答案

一尘不染

最简单的方法是使用ExecutorService.invokeAll()单行代码执行所需的操作。用你的话来说,你需要修改或包装ComputeDTask以实现Callable<>,这可以给你带来更大的灵活性。可能在你的应用中实现的有意义的实现Callable.call(),但是如果不使用,则可以通过以下方式包装它Executors.callable()

ExecutorService es = Executors.newFixedThreadPool(2);
List<Callable<Object>> todo = new ArrayList<Callable<Object>>(singleTable.size());

for (DataTable singleTable: uniquePhrases) { 
    todo.add(Executors.callable(new ComputeDTask(singleTable))); 
}

List<Future<Object>> answers = es.invokeAll(todo);

正如其他人指出的那样,invokeAll()如果合适,你可以使用的超时版本。在此示例中,answers将包含一堆Futures,这些s将返回空值(请参阅的定义Executors.callable()。可能要做的是稍微重构,以便你可以返回有用的答案或对基础的引用ComputeDTask,但是我可以从你的例子中看不出来。

如果不清楚,请注意,invokeAll()直到完成所有任务后该操作才会返回。(即,如果需要,将报告Futureanswers集合中的所有s .isDone()。)这避免了所有手动关闭,awaitTermination等…,并允许你ExecutorService根据需要在多个循环中整齐地重用此方法。

2020-03-05