I have a simple java ExecutorService
that runs some task objects (implements Callable
).
ExecutorService exec = Executors.newSingleThreadExecutor();
List<CallableTask> tasks = new ArrayList<>();
// ... create some tasks
for (CallableTask task : tasks) {
Future future = exec.submit(task);
result = (String) future.get(timeout, TimeUnit.SECONDS);
// TASKS load some classes and invoke their methods (they may create additional threads)
// ... catch interruptions and timeouts
}
exec.shutdownNow();
After all tasks are finished (either DONE or TIMEOUT-ed), I try to shutdown the executor, but it wont stop: exec.isTerminated() = FALSE.
I suspect that some tasks that are timeouted are not properly terminated.
And yes, I know that executor's shutdown is not guaranteing anything:
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via {@link Thread#interrupt}, so any task that fails to respond to interrupts may never terminate.
My question is, is there a way to ensure those (task) threads will terminate?
The best solution I came up with, is to call the System.exit()
at the end of my program, but that is plain silly.
Upon termination, an executor has no tasks actively executing, no tasks awaiting execution, and no new tasks can be submitted. An unused ExecutorService should be shut down to allow reclamation of its resources.
Using shutdown() and awaitTermination() In general, the ExecutorService will not be automatically destroyed when there is no task to process. It will stay alive and wait for new tasks to come.
In the specific case of an ExecutorService , I would vote for supporting thread interruption rather than a flag. In many frameworks, the service will be terminated with shutdownNow() .
After calling shutdown on a ExecutorService, no new Task will be accepted. This means you have to create a new ExecutorService for each round of tasks.
Recommended way from Oracle API 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();
}
If your pool is taking more time to shutdown, you can change
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
to
while (!pool.awaitTermination(60, TimeUnit.SECONDS))
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.
awaitTermination(long timeout, TimeUnit unit) throws InterruptedException:
Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With