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
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
contains several tens of thousands of elements. Should I be using another method? I am looking for something as simple as possible
Best Answer
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 wrapComputeDTask
to implementCallable<>
, which can give you quite a bit more flexibility. Probably in your app there is a meaningful implementation ofCallable.call()
, but here's a way to wrap it if not usingExecutors.callable()
.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 ofFuture
s which will return nulls (see definition ofExecutors.callable()
. Probably what you want to do is a slight refactoring so you can get a useful answer back, or a reference to the underlyingComputeDTask
, but I can't tell from your example.If it isn't clear, note that
invokeAll()
will not return until all the tasks are completed. (i.e., all theFuture
s in youranswers
collection will report.isDone()
if asked.) This avoids all the manual shutdown, awaitTermination, etc... and allows you to reuse thisExecutorService
neatly for multiple cycles, if desired.There are a few related questions on SO:
How to wait for all threads to finish
Return values from java threads
invokeAll() not willing to accept a Collection<Callable<t>>
Do I need to synchronize?
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.