I have a code where 4 threads run at the same time. I want to wait until all these 4 threads will be finished. And only after that to continue the app flow.
I tried two approaches:
Thread#join()
, this approach works as expected. The code, which comes afterjoin()
is executed only after all threads are finished.ExecutorService#shutdown()
, this technique allows executing code, which comes aftershutdown()
even if not all threads are finished.
Code sample:
ExecutorService service = Executors.newFixedThreadPool(cpuCoresNum);
for (int i = 0; i < cpuCoresNum; i++) {
service.submit(() -> {
try {
foo(); // some long execution function
} catch (Exception e) {
e.printStackTrace();
}
});
}
service.shutdown();
System.out.println("We're done! All threads are finished!");
My question:
- Why
submit()
andshutdown()
don't wait until all threads will be finished and prints «We're done! All threads are finished!» right after call ofservice.shutdown();
?
The answer is available in the ExecutorService.shutdown()
Javadoc:
This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that.
If you want to wait for the threads to finish work you have the following options:
- get
Future
instances returned bysubmit()
and callget()
on everyFuture
instance - after calling
shutdown
onservice
callawaitTermination
onservice
until it returnstrue
- instead of calling
submit
onservice
add yourRunnable
instances to ajava.util.List
and pass this list to theinvokeAll
method called onservice
Thanks to @Adam Siemion suggestions, here is a final code:
ExecutorService service = Executors.newFixedThreadPool(cpuCoresNum);
int itNum = 1;
for (int i = 0; i < cpuCoresNum; i++) {
int treadID = itNum++;
service.submit(() -> {
Thread.currentThread().setName("Thread_#" + treadID);
try {
foo();
} catch (Exception e) {
e.printStackTrace();
}
});
}
// wait until all threads will be finished
service.shutdown();
try {
service.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
Recommended way from oracle documentation page of ExecutorService:
void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
shutdown():
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
shutdownNow():
Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
In above example, if your tasks are taking more time to complete, you can change if condition to while condition
Replace
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
with
while(!pool.awaitTermination(60, TimeUnit.SECONDS)) {
Thread.sleep(60000);
}
来源:https://stackoverflow.com/questions/36376179/executorservices-shutdown-doesnt-wait-until-all-threads-will-be-finished