Best way to shutdown ExecutorService in Java - java

I am trying to write asynchronous programming in Java and I am using ExecutorService to create a pool backed by several threads to submit multiple callable tasks but I have few questions about how to shutdown the ExecutorService.
Here are my original codes:
ExecutorService executorService = Executors.newFixedThreadPool(10);
Future<String> f = executorService.submit(() -> {/*do something*/});
executorService.shutdown();
String result = f.get();
System.out.println(result);
This works good, and the executor shuts down after the threads are done. But I am worried what if write something wrong the code in callable task f.get() takes forever and the program will halt forever and never exit.
With the worry, here is my second try:
ExecutorService executorService = Executors.newFixedThreadPool(10);
Future<String> f = executorService.submit(() -> {/*do something*/});
executorService.shutdown();
if(!executorService.awaitTermination(10, TimeUnit.SECONDS)){
executorService.shutdownNow();
}
String result = f.get();
System.out.println(result);
With codes above, I can make sure threads are closed after 10 seconds. But actually the program is blocked for 10 seconds and thread may only use 5 seconds to be done.
My question is how to set the time to force to close threads in pool so that I do not need to explicitly use awaitTermination to block the program.

But I am worried what if write something wrong the code in callable
task f.get() takes forever and the program will halt forever and never
exit.
That's a bug. You need to make sure that doesn't happen.
With codes above, I can make sure threads are closed after 10 seconds
No, you can't. Even shutdownNow() doesn't actually guarantee that the executor threads are shut down (documentation):
There are no guarantees beyond best-effort attempts to stop processing
actively executing tasks. For example, typical implementations will
cancel via Thread.interrupt(), so any task that fails to respond to
interrupts may never terminate.
The ThreadPoolExecutor tries to "shut down now" by interrupting all worker threads. You need to make sure that your tasks handle interrupts correctly.
Once your tasks stop correctly, you can estimate how long a shutdown should take based on your application and the tasks you're shutting down. Then you can do a graceful shutdown:
Call shutdown()
Wait for an orderly shutdown for a reasonable amount of time using awaitShutdown()
If the executor is still running, call shutdownNow() and handle any outstanding tasks it returns.

I would like to add below points in addition to the above answers.
You can call the isDone() method of Future api before calling the get() method to verify that if the task is done as you are waiting for the task to be done via awaitTermination method of ExcuterService api.
But What I would suggest instead of using awaitTermination and shutdownNow you can use
get(long timeout, TimeUnit unit) [Waits if necessary for at most the
given time for the computation to complete, and then retrieves its
result, if available.]
of future API. It will throw TimeoutException if the timeout occurs, you may try to call shutdownNow.
you can also can check for shutdown status via isShutdown() method of ExecuterService API.

Your program should not blocked fro 10 second in your second version. It should wait for 10 seconds only if your threads does not terminate in 10 seconds. Your executor service will suspend the termination of all the threads in case of your threads does not complete in 10 seconds. From Java docs
/**
* Blocks until all tasks have completed execution after a shutdown
* request, or the timeout occurs, or the current thread is
* interrupted, whichever happens first.
*
* #param timeout the maximum time to wait
* #param unit the time unit of the timeout argument
* #return {#code true} if this executor terminated and
* {#code false} if the timeout elapsed before termination
* #throws InterruptedException if interrupted while waiting
*/

Related

cancel task, if called after shutdown, prevents awaitTermination from returning true

Consider this
LongAdder count = new LongAdder();
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
var future1 = executor.schedule(count::increment, 1800, TimeUnit.MILLISECONDS);
var future2 = executor.schedule(count::increment, 1900, TimeUnit.MILLISECONDS);
//executor.shutdown(); // line 5
System.out.println(future1.cancel(true));
System.out.println(future2.cancel(true));
//executor.purge();
executor.shutdown(); // line 9
executor.awaitTermination(1600, TimeUnit.MILLISECONDS);
System.out.println("isTerminating=" + executor.isTerminated());
System.out.println("terminated=" + executor.isTerminated());
System.out.println("count=" + count.intValue());
The program prints isTerminated=true. But if you call shutdown before cancel (i.e. comment in line 5, comment out line 9), then the program prints isTerminated=false; though if you also call purge (i.e. comment in line 8) then it prints out isTerminated=true.
Is this the expected behavior or a bug?
Expected Behaviour:
Scenario 1: You cancelled the future tasks, then shutdown appropriately, then you awaited termination so you followed the order. The tasks will cancel, and awaitTermination would succeed as it will finish before it timesout.
Scenario 2: You shutdown, without cancelling. In this case awaitingTermination will be false because not all tasks are finished/and/or/cancelled and it will timeout and return false.
Scneario 3: You shutdown, cancel, purge, awaitTermination. You actually end up removing all cancelled tasks, and awaitTermination would succeed and isTerminated would return you true as in this case (All tasks are done)
You could also do to see if awaitTermination returns true/false, to see if you actually timed out before the exector had a chance to finish after calling shutdown().
System.out.println(executor.awaitTermination(1600, TimeUnit.MILLISECONDS));
Please see the clear documentation on each of these methods and what they do.
boolean isTerminated()
Returns true if all tasks have completed following shut down. Note
that isTerminated is never true unless either shutdown or shutdownNow
was called first.
Returns:
true if all tasks have completed following shut down
Meaning it will only return TRUE if (ALL) scheduled tasks are done, simply calling shutdown will not return true.
public boolean awaitTermination(long timeout,
TimeUnit unit)
throws InterruptedException
Description copied from interface: ExecutorService Blocks until all
tasks have completed execution after a shutdown request, or the
timeout occurs, or the current thread is interrupted, whichever
happens first.
Parameters:
timeout - the maximum time to wait
unit - the time unit of the timeout argument Returns:
true if this executor terminated and false if the timeout elapsed before termination Throws:
InterruptedException - if interrupted while waiting
public void purge()
Tries to remove from the work queue all Future tasks that have been
cancelled. This method can be useful as a storage reclamation
operation, that has no other impact on functionality. Cancelled tasks
are never executed, but may accumulate in work queues until worker
threads can actively remove them. Invoking this method instead tries
to remove them now. However, this method may fail to remove tasks in
the presence of interference by other threads.

ThreadPoolExecutor shutdown API doc verbiage "does not wait"

In the documentation for ThreadPoolExector#shutdown it says:
This method does not wait for previously submitted tasks to complete execution
What does that mean?
Because I would take it to mean that queued tasks that have been submitted may not finish, but that's not what happens; see this example code, which calls shutdown before it's done starting all submitted tasks:
package example;
import java.util.concurrent.*;
public class ExecutorTest {
public static void main(String ... args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int count = i;
executorService.execute(() -> {
System.out.println("starting " + count);
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
System.out.println("interrupted " + count);
}
System.out.println("ended " + count);
});
}
executorService.shutdown();
}
}
Which prints:
C:\>java -cp . example.ExecutorTest
starting 0
starting 2
starting 1
ended 2
ended 0
starting 3
starting 4
ended 1
starting 5
ended 3
ended 5
ended 4
starting 7
starting 6
starting 8
ended 7
ended 6
ended 8
starting 9
ended 9
C:\>
In this example it seems pretty clear that submitted tasks do complete execution. I've run this on JDK8 with Oracle and IBM JDKs and get the same result.
So what is that line in the documentation trying to say? Or did somebody write this for shutdownNow and cut-n-paste it into the documentation for shutdown inadvertently?
In the doc of ThreadPoolExector#shutdown, there is one more sentence:
This method does not wait for previously submitted tasks to complete
execution. Use awaitTermination to do that.
In this context, it means the caller thread does not wait for previously submitted tasks to complete execution. In other words, shutdown() does not block the caller thread.
And if you do need block the caller thread, use ThreadPoolExector#awaitTermination(long timeout, TimeUnit unit):
Blocks until all tasks have completed execution after a shutdown
request, or the timeout occurs, or the current thread is interrupted,
whichever happens first.
Full quote of the javadoc of shutdown():
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down.
This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that.
Shutting down the executor prevents new tasks from being submitted.
Already submitted tasks, whether started or still waiting in the queue, will complete execution.
If you don't want queued tasks to execute, call 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. These tasks are drained (removed) from the task queue upon return from this method.
This method does not wait for actively executing tasks to terminate. Use awaitTermination to do that.
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. This implementation cancels tasks via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.
Whether already started tasks are stopped depends on the task, as described in the last paragraph.

Java ExecutorService - What if awaitTermination() fails?

If I have the following code, which works fine:
ExecutorService service = Executors.newFixedThreadPool(100);
[....]
List<Future<SomeObject>> futures = service.invokeAll(callables);
for (Future f : futures) {
f.get();
}
// shutdown the service after all Callables are finished.
service.shutdown();
boolean serviceIsShutDown = service.awaitTermination(5, TimeUnit.SECONDS);
if (serviceIsShutDown) {
System.out.println("Service terminated normally. All ok.");
} else {
// What if it's not shutDown?
[...]
// this?
//service = null;
}
Question: What if the call
boolean serviceIsShutDown = service.awaitTermination(5, TimeUnit.SECONDS);
returns false because the timeout hits?
I guess the Threads in the ExecutorService will remain in state WAIT. What is the best solution to continue?
Setting the service to null and having the GarbageCollector remove it? But what happens with the related Threads? Will it ever be garbage collected as there are still references?
The code usually works, but just be curious. What to do if it returns false?
If awaitTermination() returns false in your example, you have an option to try calling shutdownNow(). This method will do its best to cancel all the tasks that are still being executed, but it guarantees nothing. Some poorly implemented tasks might have no cancellation policy and just run forever. In this case, the threads will never be terminated and the executor will never be garbage collected.
Such tasks will also prevent your program from graceful termination (if you don't mark your working threads as daemons).
For instance, if your task only contains an empty infinite loop, it won't be cancelled even if you call shutdownNow().
There also might be the case that a task has no proper cancellation policy, and runs too long (but not forever). For instance, it has a very-very long empty loop. You might fail to shutdown a pool that is being executed such task by means of shutdown()/shutdownNow(), but sooner or later it will finish its work and the thread will be terminated along with the executor.
If you want to "force" the termination of your ExecutorService just use:
shutdownNow()
look here for description:

Shutting down ExecutorService

According to documentation, when shutdown() is invoked, any tasks that were already submitted (I assume via submit() or execute) will be executed. When shutdownNow() is invoked, the executor will halt all tasks waiting to be processed, as well as attempt to stop actively executing tasks.
What I would like to clarify is the exact meaning of "waiting to be processed." For example, say I have an executor, and I call execute() on some number of Runnable objects (assume all of these objects effectively ignore interruptions). I know that if I now call shutdown, all of these objects will finish executing, regardless.
However, if I call shutdownNow at this point, will it have the same effect as calling shutdown? Or are some of the objects not executed? In other words, if I want an executor to exit as fast as possible, is my best option always to call shutdownNow(), even when the Runnables passed to the executor all effectively ignore interruptions?
Let's say you have this fabulous Runnable that is not interruptible for 10 seconds once it's started:
Runnable r = new Runnable() {
#Override
public void run() {
long endAt = System.currentTimeMillis() + 10000;
while (System.currentTimeMillis() < endAt);
}
};
And you have an executor with just 1 thread and you schedule the runnable 10 times:
ExecutorService executor = Executors.newFixedThreadPool(1);
for (int i = 0; i < 10; i++)
executor.execute(r);
And now you decide to call shutdown:
The executor continues for the full 10 x 10 seconds and everything scheduled will be executed. The tasks don't see that you're shutting down their executor. shutdown can be used if you want a "short lived" executor just for a few tasks. You can immediately call shutdown and it will get cleaned up later.
Alternatively shutdownNow():
Takes 10 seconds. The already running task is attempted to be interrupted, but that obviously has no effect so it continues to run. The other 9 tasks that were still waiting in the queue are "cancelled" and returned to you as List so you could do something with them, like schedule them later. Could also take 0 seconds if the first task is not yet started. You'd get all tasks back. The method is used whenever you want to abort an entire executor.
What I would like to clarify is the exact meaning of "waiting to be processed".
It means all tasks whose run() method has not yet been called (by the executor).
If I call shutdownNow at this point, will it have the same effect as calling shutdown?
No.
Or is it possible that some of the objects will not be executed?
That is correct.
In other words, if I want an executor to exit as fast as possible, is my best option always to call shutdownNow(), even when the Runnables passed to the executor all effectively ignore interruptions?
That is correct.
Better still, recode the Runnables to pay attention to interrupts ... or put a timeout on the shutdown ...
The API for shutdownNow method says that :
There are no guarantees beyond best-effort attempts to stop processing
actively executing tasks. For example, typical implementations will
cancel via Thread.interrupt(), so any task that fails to respond to
interrupts may never terminate.
source

Program does not terminate immediately when all ExecutorService tasks are done

I put a bunch of runnable objects into an ExecutorService:
// simplified content of main method
ExecutorService threadPool = Executors.newCachedThreadPool();
for(int i = 0; i < workerCount; i++) {
threadPool.execute(new Worker());
}
I would expect my program/process to stop immediately after all workers are done. But according to my log, it takes another 20-30 seconds until that happens. The workers do not allocate any resources, in fact, they do nothing at the moment.
Don't get me wrong, this is not a crucial problem for me, I'm just trying to understand what is happening and I'm wondering if this is normal behavior.
Executors.newCachedThreadPool() uses Executors.defaultThreadFactory() for its ThreadFactory. defaultThreadFactory's javadocs say that "each new thread is created as a non-daemon thread" (emphasis added). So, the threads created for the newCachedThreadPool are non-daemon. That means that they'll prevent the JVM from exiting naturally (by "naturally" I mean that you can still call System.exit(1) or kill the program to cause the JVM to halt).
The reason the app finishes at all is that each thread created within the newCachedThreadPool times out and closes itself after some time of inactivity. When the last one of them closes itself, if your application doesn't have any non-daemon threads left, it'll quit.
You can (and should) close the ExecutorService down manually via shutdown or shutdownNow.
See also the JavaDoc for Thread, which talks about daemon-ness.
I would expect my program/process to stop immediately after all workers are done. But according to my log, it takes another 20-30 seconds until that happens. The workers do not allocate any resources, in fact, they do nothing at the moment.
The problem is that you are not shutting down your ExecutorService. After you submit all of the jobs to the service, you should shutdown the service or the JVM will not terminate unless all of the threads in it are daemon threads. If you do not shutdown the thread-pool then any threads associated with the ExecutorService, again if not daemon, will stop the JVM from finishing. If you've submitted any tasks to a cached thread pool then you will have to wait for the threads to timeout and get reaped before the JVM will finish.
ExecutorService threadPool = Executors.newCachedThreadPool();
for(int i = 0; i < workerCount; i++) {
threadPool.execute(new Worker());
}
// you _must_ do this after submitting all of your workers
threadPool.shutdown();
Starting the threads as daemon is most likely not what you want to do because your application may stop before the tasks have completed and all of the tasks will be terminated immediately at that time. I just did a quick audit and of the 178 times we use ExecutorService classes in our production code, only 2 of them were started as daemon threads. The rest are properly shutdown.
If you need to force an ExecutorService to stop when the application is exiting then using shutdownNow() with proper handling of the thread interrupt flags is in order.
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) {
...
}
From the javadoc for Executors.newCachedThreadPool():
Threads that have not been used for sixty seconds are terminated and removed from the cache.
It is usually a good idea to call shutdown() on an ExecutorService if you know that no new tasks will be submitted to it. Then all tasks in the queue will complete, but the service will then shut down immediately.
(Alternately, if you don't care if all the tasks complete - for example, if they are handling background calculations that are irrelevant once your main UI is gone - then you can create a ThreadFactory that sets all the threads in that pool to be daemon.)
For multi threading of ExecutorService
Solution is
threadPool.shutdown();
It is due to combination keepAliveTime=60L, timeunit=TimeUnit.SECONDS and corePoolSize=0*: when thread completes task, it does not terminate immediately, it may** wait during keepAliveTime for a new task.
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
*if core poolSize != 0 see method allowCoreThreadTimeOut() of ThreadPoolExecutor
**waiting depends on combination of current quantity of running threads in pool, corePoolSize and maximumPoolSize

Categories

Resources