How to wait for all threads to finish, using ExecutorService?
Solution 1
Basically on an ExecutorService
you call shutdown()
and then awaitTermination()
:
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
}
taskExecutor.shutdown();
try {
taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
...
}
Solution 2
Use a CountDownLatch:
CountDownLatch latch = new CountDownLatch(totalNumberOfTasks);
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
}
try {
latch.await();
} catch (InterruptedException E) {
// handle
}
and within your task (enclose in try / finally)
latch.countDown();
Solution 3
ExecutorService.invokeAll()
does it for you.
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
List<Callable<?>> tasks; // your tasks
// invokeAll() returns when all tasks are complete
List<Future<?>> futures = taskExecutor.invokeAll(tasks);
Solution 4
You can use Lists of Futures, as well:
List<Future> futures = new ArrayList<Future>();
// now add to it:
futures.add(executorInstance.submit(new Callable<Void>() {
public Void call() throws IOException {
// do something
return null;
}
}));
then when you want to join on all of them, its essentially the equivalent of joining on each, (with the added benefit that it re-raises exceptions from child threads to the main):
for(Future f: this.futures) { f.get(); }
Basically the trick is to call .get() on each Future one at a time, instead of infinite looping calling isDone() on (all or each). So you're guaranteed to "move on" through and past this block as soon as the last thread finishes. The caveat is that since the .get() call re-raises exceptions, if one of the threads dies, you would raise from this possibly before the other threads have finished to completion [to avoid this, you could add a catch ExecutionException
around the get call]. The other caveat is it keeps a reference to all threads so if they have thread local variables they won't get collected till after you get past this block (though you might be able to get around this, if it became a problem, by removing Future's off the ArrayList). If you wanted to know which Future "finishes first" you could use some something like https://stackoverflow.com/a/31885029/32453
Solution 5
In Java8 you can do it with CompletableFuture:
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();
user2012801
Open source projects: Java HTML compressor/minifier jQuery loading mask plugin Chrome extensions: A whole bunch Feel free to contact me at: [email protected]
Updated on July 08, 2022Comments
-
user2012801 almost 2 years
I need to execute some amount of tasks 4 at a time, something like this:
ExecutorService taskExecutor = Executors.newFixedThreadPool(4); while(...) { taskExecutor.execute(new MyTask()); } //...wait for completion somehow
How can I get notified once all of them are complete? For now I can't think about anything better than setting some global task counter and decrease it at the end of every task, then monitor in infinite loop this counter to become 0; or get a list of Futures and in infinite loop monitor isDone for all of them. What are better solutions not involving infinite loops?
Thanks.
-
Lordn__n almost 15 yearsThere aren't 4 tasks. There are "some number of tasks" done 4 at a time.
-
user2012801 almost 15 yearsOnly instead of CountDownLatch(4) I need to use number of total threads created, right?
-
ChssPly76 almost 15 yearsSorry, I misunderstood the question. Yes, number of tasks should be the argument to CountDownLatch constructor
-
user2012801 almost 15 yearsLooks nice and simple, only I have feeling that shutdown here is used not for what it was designed (or it is fine?).
-
Lordn__n almost 15 yearsIt's a common pattern. Transient threadpools like the above are good for several reasons and I pretty much always prefer them to persistent threadpools where a lot more can go wrong or at least it can be harder to figure out. The above is really straightforward which is why I like it.
-
wvdschel almost 15 yearsI find this solution more elegant than the others, it looks like it was made for this purpose, and it's simple and straightforward.
-
Lordn__n almost 15 yearsWhat if you don't know the number of tasks before you start?
-
matt b almost 15 yearsthis is exactly what shutdown / awaitTermination are meant for
-
ChssPly76 almost 15 years@cletus - then you don't use a CountDownLatch :-) Mind you, I'm not arguing that this approach is better than yours. However, I found that in real life scenarios I do know the number of tasks, thread pool settings do need to be configurable per deployment, and pools can be reused. So I usually have thread pools injected by Spring and setting them as prototypes and manually shutting them down only in order to wait for threads to finish seems less than ideal.
-
sjlee almost 15 yearsIt is a good pattern if this task handling is a one-time event. If this is done repeatedly during the same runtime, however, it is not optimal, as you would create and tear down threads repeatedly every time it is executed.
-
象嘉道 almost 13 yearsThis pattern is incomplete: Some unsubmitted tasks may be never executed.
-
inanutshellus over 12 years@Kejia It is not incomplete... Think about it this way: Your main thread is spawning off subthreads in a loop. When it's done adding, you run this code. You might see output out of order, but all of your tasks will have been spun off. Thanks @Cletus!
-
נשמה קשוחה over 12 yearsCool, can never remember the name of this data structure. However, only suitable if you know beforehand the amount of tasks that will get queued.
-
Sam Harwell over 11 yearsI'm looking for any official documentation that
Long.MAX_VALUE, TimeUnit.NANOSECONDS
is equivalent to not having a timeout. -
Brad over 11 years@serg is this still considered the best answer over using
invokeAll()
as proposed by sjlee? -
rogerdpack over 11 yearsI can't believe that you have to use shutdown in order to join on all the current threads (after using shutdown, you cannot use the executor again ever). Suggest using list of Future's instead...
-
rogerdpack over 11 yearsThe difficulty comes if/when you have the start the "4" threads one at a time, piece-wise, then join/let finish all 4...
-
rogerdpack over 11 yearsyeah you'd think you'd be able to hit the barrier with the current thread, and all the child threads, then when you passed it you'd know the child threads were done...
-
Andrew Mao over 11 yearsThis does seem to be better than
shutdown
/awaitTermination
.CyclicBarrier
also seems to be useful when you need to run threads in groups at a time. -
jontejj almost 11 yearsAs I'm testing this out I found that the executor finishes before all tasks have completed. If I use Thread.sleep(100) before calling shutdown() it works. So I suspect that there may be some timing issues with your code if the time between adding tasks to the shutdown call is too small.
-
Nazgul over 10 yearsthis wont work if you dont want to shutdown the executor. For a perpetually running batch kind of thing u need to submit jobs and wait for them to finish before jumping ahead. In Such a case a latch or a barrier makes more sense than a shutdown.
-
gerrytan over 10 yearsIMO it's probably not a wise thing to NOT have a timeout. There's always a likelihood your task is stuck / deadlocking and the user would wait forever.
-
Mukul Goel over 9 years@rogerdpack: I am still learning this executors and stuff. But in response to what you ask. Should the 4 threads at a time not be part of a batch task which is executed using the answer above?
-
Konstantin over 9 yearsThis method will only work if you know the number of tasks before hand.
-
Olivier Faucheux about 9 yearsNot a good idea, see stackoverflow.com/a/7271685/1166992 and the javadoc: "Returns the approximate number of threads that are actively executing tasks."
-
Zero3 almost 9 years@ashutosh I can't find any documentation on this. It appears to be a method of a Spring library, and not plain Java functionality.
-
beluchin over 8 years@SamHarwell see the
java.util.concurrent
package documentation under theTiming
section: To wait "forever", you can use a value ofLong.MAX_VALUE
-
ToolmakerSteve over 8 yearsTo know which "finishes first", use
ExecutorCompletionService.take
: stackoverflow.com/a/11872604/199364 -
ToolmakerSteve over 8 yearsTook me awhile to see how this would solve OP's question. First, note that this wrapping is of each task, not of the code that starts all the tasks. Presumably, each start would increment a counter, and each finish would decrement that counter, or would increment a
completed
counter. So after starting them all, at each notification, could determine whether all tasks have completed. Note that it is vital to usetry/finally
so that a finished notification (or an alternative notification incatch
block) is given even if a task fails. Otherwise, would wait forever. -
ToolmakerSteve over 8 yearsIt is good that you show use of future.get -- good alternative to know about. But why do you consider it better to wait forever, than to set some maximum acceptable timeout? More importantly, there is no reason to do all this logic, when one can simply give a really, really long time to awaitTermination, if you want to wait (essentially forever) until all tasks complete.
-
ToolmakerSteve over 8 yearsOn seeing this, I first wondered if it would be a problem if some
release
calls happen before theacquire
call, but after reading Semaphore documentation, I see that is okay. -
ToolmakerSteve over 8 years@ashutosh 1) That requires springframework. 2) Doesn't look any simpler to me than shutdown/awaitTermination.
-
ToolmakerSteve over 8 yearsstryba's Semaphore solution is more flexible, as it accomplishes the same result (no need to shutdown) as CountDownLatch, without needing to know how many tasks there are.
-
Praveen Kumar over 8 yearsIs it better than using infinite loop while checking isTerminated() ?
-
Saurabh over 8 years+1,thanks it helped, also referred this howtodoinjava.com/core-java/interviews-questions/…
-
Coder about 8 yearsIf I don't want to shutdown because I want to keep my executor alive. How can I know the maximum number of pending tasks that could I have there?
-
Tim Malone almost 8 yearsHi Vlad, welcome to StackOverflow. Can you please edit your answer to explain how this answers the question, and what the code does? Code only answers are discouraged here. Thank you!
-
AlikElzin-kilaka over 7 yearsI think that when the
futures
are returned, the tasks haven't been completed. They might complete in the future and you'll have a link to the result. That's why it's called aFuture
. You have the method Future.get(), which will wait for the task to finish to get a result. -
hinneLinks over 7 years@SamHarwell
TimeUnit.NANOSECONDS
andLong.MAX_VALUE
equals 106,751 Days or 292 years (TimeUnit.NANOSECONDS.toDays(Long.MAX_VALUE);
), that should be enough, or use some of the bigger TimeUnits. -
gstackoverflow about 7 yearsActually it is wrong answer. CyclicBarrier designed for portions. CountDownLatch designed for waiting event
-
DSchmidt about 7 yearsVery clean. Does work flawlessly even on Android. Just had to use
runOnUiThread()
inonSuccess()
. -
Manish Kumar Sharma almost 7 yearsThis is not different from already presented solutions here. Your just solution is the same as presented by @sjlee
-
eli-bd almost 7 yearsWhen sizing thread pools, it is often useful to base the size on the number of logical cores in the machine running the application. In Java, you can get that value by calling Runtime.getRuntime().availableProcessors(). In this case, it would be Math.min(4, Runtime.getRuntime().availableProcessors());
-
Hulk over 6 years@AlikElzin-kilaka Quote from the JavaDocs (linked in the answer): "Executes the given tasks, returning a list of Futures holding their status and results when all complete. Future.isDone() is true for each element of the returned list."
-
Mashrur over 6 yearsNot sure why you need to check for done when according to oracle doc, invokeAll will return only "when all complete or the timeout expires, whichever happens first"
-
Gili over 6 yearsAnother major advantage of this approach is that it works with shared
Executor
s that cannot simply be shut down because they are used by others. -
mattvonb about 6 yearsThis is a very elegant solution.
-
Jobs about 6 yearsexecutor.shutdown(); is stopping my program !!
-
user2862544 over 5 years
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 } }
-
The Gilbert Arenas Dagger over 5 yearsNote that executorService.invokeAll will wait for all threads to complete, but you will still need to call executorService.shutdown to clean up your thread pool.
-
Mobigital almost 5 yearsJava apis are pretty terrible. Thank you for this insight.
-
GabrielBB over 4 yearsThis post talks about concurrency. Parallelism != Concurrency
-
Gaurav over 4 years@cletus is awaitTermination() necessary after shutdown()?
-
Gaurav over 4 years@AdamSkywalker is awaitTermination() necessary after es.shutdown()?
-
Gaurav over 4 yearsis awaitTermination() necessary after shutdown()/
-
AdamSkywalker over 4 years@gaurav when you call shutdown, some tasks may not be finished yet. So awaitTermination will block the calling thread until everything is done. It depends on whether you need to wait for results in this thread or not.
-
Gaurav over 4 years@AdamSkywalker great answer. makes sense to not call awaitTermination() if I dont need to wait for the results.
-
nagendra547 over 4 years@AdamSkywalker Great answer!! Elegant!
-
Alfredo Zuloaga about 3 yearsWhat if you simply add finally and there put your latch.CountDown()
-
Siddhartha over 2 yearsEven better to make the future.get call timed
future.get(10, TimeUnit.SECONDS);
and catch the TimeoutException -
ryanlee over 2 yearsthis method has one serious problem is that once the thread pool commit task error and refuse it, it can never go out because the countDown in task can not be executed