ThreadPoolExecutor shutdown API doc verbiage "does not wait" - java

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.

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.

Best way to shutdown ExecutorService in 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
*/

what is the best way to wait ThreadPoolExecutor finish thread in java?

I an using ThreadPoolExecutor in java to excute multi threads, and I have to do something after threads finish, and have to wait.
So I want to ask what is the best way to do that?
Is that right I do in the way?
threadPool.shutdown();
boolean loop = true;
Integer x = threadPool.getPoolSize();
while (threadPool.getPoolSize() != 0) {
}
Shutdown will initiate an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
executor.shutdown();
System.out.println("All tasks submitted...No new tasks will be admitted");
However, I would strongly recommend using awaitTermination as this will allow current thread to block until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
try {
executor.awaitTermination(3, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
EDIT:
The runState provides the main lifecyle control, taking on values:
* RUNNING: Accept new tasks and process queued tasks
* SHUTDOWN: Don't accept new tasks, but process queued tasks
* STOP: Don't accept new tasks, don't process queued tasks,
* and interrupt in-progress tasks
* TIDYING: All tasks have terminated, workerCount is zero,
* the thread transitioning to state TIDYING
* will run the terminated() hook method
* TERMINATED: terminated() has completed
The numerical order among these values matters, to allow ordered comparisons. The runState monotonically increases over time, but need not hit each state.
The transitions are:
RUNNING -> SHUTDOWN
On invocation of shutdown(), perhaps implicitly in finalize()
(RUNNING or SHUTDOWN) -> STOP
On invocation of shutdownNow()
SHUTDOWN -> TIDYING
When both queue and pool are empty
STOP -> TIDYING
When pool is empty
TIDYING -> TERMINATED
When the terminated() hook method has completed. Threads waiting in awaitTermination() will return when the state reaches TERMINATED.
Detecting the transition from SHUTDOWN to TIDYING is less straightforward than you'd like because the queue may become empty after non-empty and vice versa during SHUTDOWN state, but we can only terminate if, after seeing that it is empty, we see that workerCount is 0.
Going back to your question, when you call getPoolSize() it checks the state of the threadpool when it is in TIDYING state. Hence, I think the correct check should be against TERMINATED state. Although, the results are the same if you have not implemented terminated() method.
If you want to wait gracefully, refer to solutions in below question:
How to wait for completion of multiple tasks in Java?
If you are not using any of them ( invokeAll, CountDownLatch) and submit the jobs and waiting for executor to finish the tasks, refer to
How to forcefully shutdown java ExecutorService
Basic code snippet in this case:
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();
}

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

Difference between shutdown and shutdownNow of Executor Service

I want to know the basic difference between shutdown() and shutdownNow() for shutting down the Executor Service?
As far as I understood:
shutdown() should be used for graceful shutdown which means all tasks that were running and queued for processing but not started should be allowed to complete
shutdownNow() does an abrupt shut down meaning that some unfinished tasks are cancelled and unstarted tasks are also cancelled. Is there anything else which is implicit/explicit that I am missing?
P.S: I found another question on How to shutdown an executor service related to this but not exactly what I want to know.
In summary, you can think of it that way:
shutdown() will just tell the executor service that it can't accept new tasks, but the already submitted tasks continue to run
shutdownNow() will do the same AND will try to cancel the already submitted tasks by interrupting the relevant threads. Note that if your tasks ignore the interruption, shutdownNow will behave exactly the same way as shutdown.
You can try the example below and replace shutdown by shutdownNow to better understand the different paths of execution:
with shutdown, the output is Still waiting after 100ms: calling System.exit(0)... because the running task is not interrupted and continues to run.
with shutdownNow, the output is interrupted and Exiting normally... because the running task is interrupted, catches the interruption and then stops what it is doing (breaks the while loop).
with shutdownNow, if you comment out the lines within the while loop, you will get Still waiting after 100ms: calling System.exit(0)... because the interruption is not handled by the running task any longer.
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.submit(new Runnable() {
#Override
public void run() {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("interrupted");
break;
}
}
}
});
executor.shutdown();
if (!executor.awaitTermination(100, TimeUnit.MICROSECONDS)) {
System.out.println("Still waiting after 100ms: calling System.exit(0)...");
System.exit(0);
}
System.out.println("Exiting normally...");
}
shutdown():
To terminate the threads inside the ExecutorService you call its shutdown() method. The ExecutorService will not shut down immediately, but it will no longer accept new tasks, and once all threads have finished current tasks, the ExecutorService shuts down. All tasks submitted to the ExecutorService before shutdown() is called, are executed.
shutdownNow():
If you want to shut down the ExecutorService immediately, you can call the shutdownNow() method. This will attempt to stop all executing tasks right away, and skips all submitted but non-processed tasks. There are no guarantees given about the executing tasks. Perhaps they stop, perhaps the execute until the end. It is a best effort attempt.
From the javadocs:
void shutdown
Initiates an orderly shutdown in which previously submitted tasks are
executed, but no new tasks will be accepted.
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.
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.
Returns: list of tasks that never commenced execution

Categories

Resources