As per Javadocs, shutdown() will wait for all submit tasks to be executed. I have two questions:
What does submitted task mean? Do the tasks have to be submitted specifically by ExecutorService.submit() method or it included tasks submitted by ExecutorService.execute() method also?
I have added a shutdown hook which calls ExecutorService.shutdown(). As per the docs, it should wait for all submit tasks to be executed. But it doesn't until I add a awaitTermination() call after the shutdown() call. Why doesn't it execute all tasks without awaitTermination() call?
What does submitted task mean? Do the tasks have to be submitted specifically by ExecutorService.submit() method or it included tasks submitted by ExecutorService.execute() method also?
A 'submitted' task in this sense is any Runnable or Callable that was passed to the ExecutorService. Although the wording of the javadoc is slightly confusing, it does not differentiate between execute() vs submit().
I have added a shutdown hook which calls ExecutorService.shutdown(). As per the docs, it should wait for all submit tasks to be executed. But it doesn't until I add a awaitTermination() call after the shutdown() call. Why doesn't it execute all tasks without awaitTermination() call?
The shutdown() operation is non-blocking (asynchronous) as are almost all of the methods on the ExecutorService API. The javadoc only states that calling shutdown() will initiate a shutdown sequence.
The key here is that the ExecutorService will try to wait for all tasks to complete, but if shutdown() is the last line of code before your main method terminates, System.exit() will be called after the end of your main method which will terminate the JVM and override the ExecutorService's attempt to wait for running tasks to complete. I would consider it undesireable for ExecutorService.shutdown() to always delay a System.exit(), and would prefer an opt-in approach to a blocking call (i.e. awaitTermination).
Related
This question already has answers here:
ExecutorService, how to wait for all tasks to finish
(16 answers)
Closed 5 years ago.
I am in the process of writing a code where whenever a folder is encountered it is supposed to start a new thread. The code looks like,
p
ublic void diff(File x,File y){
ThreadPoolExecutor executor=new ThreadPoolExecutor(10,30,2000,unit,BlockingQueue<Runnable> queue)
if(x.isDirecotry && y.isDirectory){
Runnable thread=new DThread(x,y);
Future<?> result=executor.submit(thread);
if(result.isDone()){
LOGGER.debug(thread.toString()+"has completed");
}
I am using ThreadPoolExecutor for this purpose. If I shutdown the ThreadPoolExecutor then it will not take up any new Threads. But there is a possibility of new threads starting after starting. If I do not shutdown the ThreadPoolExecutor then all the threads are executed but in the end the JVM is not terminating.
Please help how can I shutdown the threadPool only when all the threads are executed so that the JVM gets terminated. Also suggest if there is better way of implemention of thread pool.I want to use thread pool so that I can use threads from the pool instead of creating new thread everytime.
The things that you are submitting should not be threads (subtypes of Thread). They should be simple tasks: implementations of Runnable or Callable.
The way to shutdown the executor is to call shutdown() or shutdownNow() on it. The javadoc summary says:
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.
The latter attempts to stop the tasks by interrupting them. However, if the task code does not check for interrupts, it will run to completion. (It also stops accepting new tasks.)
It sounds like shutdown() does what you want to do.
The problem lies in the fact where should I place the shutdown method.
You call it when you want to start shutting down.
Because there is a possibility that new threads may be coming after shutdown is being called.
Stop calling them threads. They are tasks.
Any tasks that are submitted after shutdown() has been called are rejected.
My question is how can I check whether all the tasks have finished executing and only then call shutdown. If I call with the initiation of each task then it will not allow new tasks later on.
The correct time to call shutdown() is when your application has finished submitting tasks to the executor.
Maybe your conceptual problem is the scoping of the executor service. Your example code seems to show that each call to diff is creating a new service object. That means that you would have lots of independent thread pools ... and no reuse of threads. What you should really do is to create a "global" thread pool and have multiple calls to diff submit tasks to the same pool.
I need to do something like this:
ExecutorService executor = Executors.newFixedThreadPool(2);
CompletionService<Boolean> completionService = new ExecutorCompletionService<>(executor);
int i = 0;
while (i < 40) {
completionService.submit(getTask());
i++;
}
executor.shutdown();
System.out.println("SHUTDOWN");
But after calling shutdown on executor object completionService still execute tasks.
How can I make it stop?
Is there are any way to stop ExecutorService but wait for the completion of currently executing tasks?
The ExecutorService will carry on executing tasks already submitted but will not allow further tasks to be submitted, from the documentation
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.
emphasis mine
So you have already submitted 40 tasks, these will be executed before shutdown.
If you want to force shutdown. You can use 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.
emphasis mine
Which will abandon scheduled tasks, as you want.
N.B.: Stopping tasks in progress is another issue entirely.
Use shutdownNow() which will try to stop already executing task. Read this https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#shutdownNow()
The shutdown of already executing task is an attempt only but will not be guaranteed to stop.
The shutdown() method only stops taking new tasks but already executing task will continue to execute.
UPDATE for the "Is there are any way to stop ExecutorService but waiting for completion currently executed tasks?"
One option I can think of is this -
The completionService.submit(getTask()); return object of type Future. You can write code to check if the task isDone(). After calling shutdownNow() you can check the tasks in a loop for isDone(). You need to store the tasks in list when returned by submit method.
ScheduledExecutorService inherits two methods from the ExecutorService, shutdown() and shutdownNow(). The difference between them:
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.
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.
Now I want to halt processing of waiting tasks while I don't want to interrupt currently executing tasks. I can't interrupt the threads because third party libraries are involved and they don't deal well with interrupts :-( But I need to cancel scheduled tasks, that are not currently executing since most of them are scheduled in an hour or so.
What's the best way to deal with this? What options Do I have?
Sounds like calling setExecuteExistingDelayedTasksAfterShutdownPolicy(false) on your executor should do the trick:
Sets the policy on whether to execute existing delayed tasks even when
this executor has been shutdown. In this case, these tasks will only
terminate upon shutdownNow, or after setting the policy to false when
already shutdown. This value is by default true.
Since it's true by default, these tasks are executed. If you set it to false, they shouldn't be executed any more. This shouldn't be confused with submitted tasks which the docs you quote refer to. They are just waiting in the queue to be executed right away, when there is a free worker.
I am using ExecutorService in Java web server application for executing some computational tasks in parallel style and then calling shutdown() with awaitTermination() to wait for all tasks to be done. Whole computation can sometimes take dozens of minutes.
The thing is awaitTermination() method blocks the main thread until timeout elapsed (or interrupted) but I just want to start the tasks and immediatedly respond to client and after competition of all tasks shutdown the service (following conventions to always close the thread pool).
So my question, is there a way how I can be notified when all tasks are done so I could call the shutdown() method? Listener or something..
Thanks!
You are trying to solve a problem that doesn’t exist. Consider the documentation of ExecutorService.shutdown():
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. …
This method does not wait for previously submitted tasks to complete execution.
In other words, just calling shutdown() does already everything you want
It finishes all previously submitted tasks
It initiates a shutdown
It does not wait
The only obstacle is that you are calling awaitTermination despite the fact that you don’t want to wait, which has a trivial solution: don’t call awaitTermination.
The confusion arises because in your question you are asking “how I can be notified when all tasks are done so I could call the shutdown() method” but that is in contradiction to what you are actually doing in the code. You are calling awaitTermination after shutDown so you are not waiting in order to initiate the shutdown, but initiating the shutdown first and waiting for its completion then, which is the purpose of awaitTermination, waiting for the completion of the shutdown.
To put it in one sentence, just call shutDown after submission in order to shutdown the service after completion of all submitted jobs and don’t call awaitTermination unless you really want to wait for the termination.
Thanks to comment from VGR I solved my problem with creating yet another Thread in which I wrapped my existing code like this:
Thread thread = new Thread(() -> {
ExecutorService service = Executors.newCachedThreadPool();
collection.forEach(item -> service.submit(() -> {
// some computational work
});
try {
service.shutdown()
service.awaitTermination(2, TimeUnit.HOURS);
catch (InterruptedException iEx) {
// handle exception
}
});
thread.start();
return ResponseToClient();
If I submit some tasks to an Executor using invokeAll, am I guaranteed that the submitted thread sees all the side effects of the task executions, even if I don't call get() on each of the returned Futures?
From a practical point of view, it would seem that this would be a useful guarantee, but I don't see anything in the javadoc.
More precisely, do all actions in the body of a Callable submitted to an executor happen-before the return from the invokeAll() call?
It's annoying to uselessly call get() on each future, when in fact the return type is Void and no exceptions are thrown - all the work in the happens as side-effects.
From the documentation of ExecutorService:
Actions in a thread prior to the submission of a Runnable or Callable
task to an ExecutorService happen-before any actions taken by that
task, which in turn happen-before the result is retrieved via
Future.get().
As I read this, there is a memory barrier on task submission, so potentially you'd need to call get() on the last task in your list to, but not the others.
However, since calling get() is the only way to determine whether the task completed or threw, I would still call it on every Future, regardless of memory guarantees.
If invokeAny() promises that no tasks are still in execution when invokeAny() returns, this will be the case: all side effects are visible.
In order for invokeAny() to know that all tasks are done, it needs to have synchronized with those threads, meaning that the returning of the functions happens after the tasks completing (and everything that happens in the task). However the API of 'ExecutorSerive' and 'Future.cancel()' does not explicitly say what happens when you cancel a running task (in particular: will cancel() wait with returning until the tasks has stopped running. The fact that after calling cancel(), isDone() must return true, does imply that cancel() will not return until the task has actually finished executing.
One more thing to watch out for is that you will not know if a task ever started execution, when using invokeAny() without inspecting the Future objects.