本文介绍了ExecutorService,如何等待所有任务完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

等待 ExecutorService 的所有任务完成的最简单方法是什么?我的任务主要是计算,所以我只想运行大量作业——每个内核一个.现在我的设置看起来像这样:

What is the simplest way to to wait for all tasks of ExecutorService to finish? My task is primarily computational, so I just want to run a large number of jobs - one on each core. Right now my setup looks like this:

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.这很奇怪,因为我玩了一些玩具示例并且它似乎有效.

ComputeDTask implements runnable. This appears to execute the tasks correctly, but the code crashes on wait() with IllegalMonitorStateException. This is odd, because I played around with some toy examples and it appeared to work.

uniquePhrases 包含数万个元素.我应该使用另一种方法吗?我正在寻找尽可能简单的东西

uniquePhrases contains several tens of thousands of elements. Should I be using another method? I am looking for something as simple as possible

推荐答案

最简单的方法是使用 ExecutorService.invokeAll() 它可以在单行中执行您想要的操作.按照您的说法,您需要修改或包装 ComputeDTask 以实现 Callable,这可以为您提供更大的灵活性.可能在您的应用程序中有一个有意义的 Callable.call() 实现,但如果不使用 Executors.callable().>

The simplest approach is to use ExecutorService.invokeAll() which does what you want in a one-liner. In your parlance, you'll need to modify or wrap ComputeDTask to implement Callable<>, which can give you quite a bit more flexibility. Probably in your app there is a meaningful implementation of Callable.call(), but here's a way to wrap it if not using 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 将包含一堆 Future 将返回空值(参见 Executors.callable() 的定义.可能你想要做的是轻微的重构,这样你就可以得到一个有用的答案,或者对底层 ComputeDTask 的引用,但我无法从你的例子中看出.

As others have pointed out, you could use the timeout version of invokeAll() if appropriate. In this example, answers is going to contain a bunch of Futures which will return nulls (see definition of Executors.callable(). Probably what you want to do is a slight refactoring so you can get a useful answer back, or a reference to the underlying ComputeDTask, but I can't tell from your example.

如果不清楚,请注意 invokeAll() 直到所有任务都完成后才会返回.(即,如果询问,answers 集合中的所有 Future 将报告 .isDone().)这避免了所有手动关闭,awaitTermination等...并允许您根据需要在多个循环中巧妙地重用此 ExecutorService.

If it isn't clear, note that invokeAll() will not return until all the tasks are completed. (i.e., all the Futures in your answers collection will report .isDone() if asked.) This avoids all the manual shutdown, awaitTermination, etc... and allows you to reuse this ExecutorService neatly for multiple cycles, if desired.

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

There are a few related questions on SO:

从 Java 线程返回值

invokeAll() 不愿意接受一个集合<可调用>

我可以吗需要同步吗?

这些都不是严格针对您的问题,但它们确实提供了一些关于人们认为应该如何使用 Executor/ExecutorService 的颜色.

None of these are strictly on-point for your question, but they do provide a bit of color about how folks think Executor/ExecutorService ought to be used.

这篇关于ExecutorService,如何等待所有任务完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-02 21:57