执行器服务,如何等待所有任务完成

等待所有任务完成的最简单方法是什么?我的任务主要是计算,所以我只想运行大量的作业 - 每个内核一个。现在我的设置如下所示: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包含数万种元素。我应该使用其他方法吗?我正在寻找尽可能简单的东西


答案 1

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

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);

正如其他人所指出的,如果合适,您可以使用 超时版本。在此示例中,将包含一堆将返回 null 的 s(请参阅 的定义。也许你想做的是稍微重构,这样你就可以得到一个有用的答案,或者对底层的引用,但我无法从你的例子中看出。invokeAll()answersFutureExecutors.callable()ComputeDTask

如果不清楚,请注意,在所有任务完成之前,它不会返回。(即,如果系统询问,您收藏中的所有 s 都将报告。这避免了所有手动关机,等待终止等...并允许您根据需要在多个周期中整齐地重复使用它。invokeAll()Futureanswers.isDone()ExecutorService

关于 SO 有几个相关的问题:

这些都不是严格意义上的,但它们确实提供了一些关于人们如何思考/应该如何使用的颜色。ExecutorExecutorService


答案 2

如果要等待所有任务完成,请使用 shutdown 方法而不是 。然后用等待终结来跟随它。wait

此外,还可以使用 Runtime.availableProcessors 来获取硬件线程数,以便正确初始化线程池。