Java ExecutorService - What if awaitTermination() fails? - java

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:

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.

Cleaning up thread submitted using ExecutorService

My code is as follows:
public Future<String> getFuture() {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> future = executorService.submit(() -> {
//do something
return "test string";
});
executorService.shutDown(); // is this correct?
return future;
}
I am calling this service from other class to get the future:
Future<String> future = getFuture();
String result = future.get();
future.cancel(true); // will this assure that there wont be any thread leak?
Now out of executorService.shutDown() and future.cancel(true) which will assure that there wont be thread leaks?
Note that after calling future.cancel(true) when I check currently running threads in the result of Thread.getAllStackTraces() I can still find the thread where future executed.
You are asking the wrong question!
There is no point in creating a service within a method to then throw it away right there.
Creating that service instance doesn't come for free. The whole idea of this abstraction is to ensure to make efficient usage of infrastructure elements!
In other words: step back and rework your design; so that this service becomes a field of some class for example! And yes, that might turn out to be complicated. But most likely, spending time in that corner will pay out much more long term - compared to continuing the approach shown in your question.
It is a bad idea to create an executor then throw it away in each method call.
Now out of executorService.shutDown() and future.cancel(true) which will assure that there wont be thread leaks?
none of them.
executorService.shutdown() will just keep running the current tasks and reject new submitted tasks.
future.cancel(true) will interrupt the corresponding task if it is currently running (but it is your responsability to check if the task was interrupted and finish the execution of the task as soon as possible)
Note that after calling future.cancel(true) when I check currently running threads in the result of Thread.getAllStackTraces() I can still find the thread where future executed.
as I mentioned before, future.cancel(true) doesn't stop the thread. it only sends an interruption.

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

Does awaitTermination in ExecutorService "happens-before" any code executed after it?

Please, help to understand ExecutorService#awaitTermination(timeout) behaviour.
I'm observing situation when I have in my code:
private void shutdownAndAwaitTermination(ExecutorService threadPool){
threadPool.shutdown();
try {
if (!threadPool.awaitTermination(threadPoolTimeout, TimeUnit.HOURS)){
threadPool.shutdownNow();
if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
logger.warn("Pool did not terminate");
}
}
}
catch (InterruptedException ie) {
threadPool.shutdownNow();
Thread.currentThread().interrupt();
}
}
Does the tasks in pool complete in this case before any other calls after shutdownAndAwaitTermination() in same thread ?
Looking into what is happening on production, I believe that the answer is no, but I just want to understand how to make sure that any code placed after call to shutdownAndAwaitTermination() will happen after last task in pool completes.
Thanks.
No, tasks could definitely complete after you return from your shutdownAndAwaitTermination() method, because you don't actually await termination. If the waiting thread is interrupted, or if it takes too long, you stop waiting, even though tasks may still be running.
Even if you call shutdownNow(), your tasks may not respond to interruption (and in general, ExecutorService isn't guaranteed to use interruption). So tasks may still be running.
If you want to ensure task completion happens-before returning from this method, you have to keep trying until awaitTermination() returns true, in spite of interrupts, etc. That would be a bad design, so it would be better if your tasks returned their results via a Future instead of producing side-effects non-atomically. That way, tasks that complete successfully can be acted upon, while tasks that do not complete can be ignored.
from http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html:
List<Runnable> 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.
This method does not wait for actively executing tasks to terminate.
Use awaitTermination to do that.
There is no way to accurately stop running thread, so you have to wait for already running tasks to finish.

How do I interrupt a thread given a Future object?

I want to start a thread and cancel it if it doesn't finish within 5 seconds:
private final class HelloWorker implements Callable<String> {
public String call() throws Exception {
while(true) {
if (Thread.isInterrupted()) {
return null;
}
}
return performExpensiveComputation();
}
private String performExpensiveComputation() {
// some blocking expensive computation that may or may not take a very long time
}
}
private ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
Future<String> future = executorService.submit(new HelloWorker());
try {
String s = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
future.cancel(true);
System.out.println("cancelled: " + future.isCancelled() + "done: " + future.isDone());
executorService.shutdown();
try {
System.out.println("try to terminate: " + executorService.awaitTermination(60, TimeUnit.SECONDS));
} catch (Exception ex) {
// ignore
}
}
However it looks like the awaitTermination returns false. Is there a way for me to check why an ExecutorService won't terminate? Can I figure out what threads are still running?
There is no safe way to stop a running thread without disturbing the stability of the rest of the process. This is why Thread#stop has been deprecated a long time ago, and why Executor Services only use the soft, cooperative Thread#interrupt mechanism.
Your thread will have to actively check if an interrupt has been requested and perform proper cleanup before ending. Alternatively, the thread will call some interruptible JDK methods, which will throw InterruptedException, which the tread will properly honor and end itself.
Why Future.cancel() doesn't work the way you think it does
Future cancel removes the task from the running queue. If your task is already running it won't stop it. So cancel() is a different concept that interrupting. As the Javadocs say:
Attempts to cancel execution of this task. This attempt will fail if
the task has already completed, has already been cancelled, or could
not be cancelled for some other reason. If successful, and this task
has not started when cancel is called, this task should never run. If
the task has already started, then the mayInterruptIfRunning parameter
determines whether the thread executing this task should be
interrupted in an attempt to stop the task.
https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/concurrent/Future.html#cancel(boolean)
What you are asking is how to interrupt. Fortunately, when you call Future.cancel() it will call the interrupt method. But you'll need to allow it with the mayInterruptIfRunning flag and will need to handle interrupts correctly (see below).
Why interrupt?
Interrupting threads in Java is useful when you have a long running task that you now need to stop, or when you have a daemon that you need to turn off, and other examples.
How to interrupt
To interrupt you call interrupt() on the thread. This is a cooperative process, so your code has to be ready for it. Like this:
myThread.interrupt();
Responsible code
Your code's responsibility is to be ready for any interruptions. I'd go so far to say that whenever you have a long running task, that you insert some interrupt ready code like this:
while (... something long...) {
... do something long
if (Thread.interrupted()) {
... stop doing what I'm doing...
}
}
How to stop what I'm doing?
You have several options:
If your you are in Runnable.run() just return or break out of the loop and finish the method.
You may be in some other method deep in the code. It may make sense at that point for that method to throw InterruptedException so you would just do that (leaving the flag cleared).
But maybe deep in your code it doesn't make sense to throw InterruptedException. In that case you should throw some other exception, but before that mark your thread interrupted again so the code that catches knows that an interrupt was in progress. Here's an example:
private void someMethodDeepDown() {
while (.. long running task .. ) {
... do lots of work ...
if (Thread.interrupted()) {
// oh no! an interrupt!
Thread.currentThread().interrupt();
throw new SomeOtherException();
}
}
}
Now the exception can propagate an either terminate the thread or be caught, but the receiving code hopefully notices that an interrupt is in progress.
Should I use isInterrupted() or interrupted()
You should prefer interrupted() because:
Your code should reset the interrupt flag because if you don't the thread you are using could go back to a thread pool with an interrupted state causing problems (of course, that's a bug in the thread pool code, you won't get that behavior if you use Executors.newFixedThreadPool() for example. But other threading code could have it.
As another answer stated, the clearing of the interrupted flag indicates that you've received the message and are taking action. If you leave it on true, the after a while caller can assume you won't respond to it in a timely manner.
Why interrupt() why not some other flag in my code?
Interrupt is the best mechanism for interruption because our code can be ready for it. If we find code that is just catching and ignoring the InterruptExceptions or not checking for interrupted() in its body then we can correct those mistakes and make our code always cleanly interruptible without creating arcane dependencies on non-standard mechanisms in your code.
Unfortunately Joshua Block proposed the opposite in his famous book Effective Java, Second Edition. But enabling the interrupt() method to work as intended is much better, because this code is used by the Java standard library as explained above. A custom interruption method would not be.

Categories

Resources