Difference Between Shutdown and Shutdownnow of Executor Service

Difference between shutdown and shutdownNow of Executor Service

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...");
}

Comparison between shutting down an executor service (while awaiting termination) and wait cancellation of submitted tasks (using submit's futures)

In the proposed solution, wait should be called after shutdownNow() method invocation.

An unused ExecutorService should be shut down to allow reclamation of
its resources.

shutdownNow():-

  • Transition the run state to Stop
  • Interrupt the worker if started
  • Drain the queue - Remove all the threads

Future.cancel (false):-

  • Doesn't interrupt the running tasks
  • The cancel attempt will fail if the task has already completed, has
    already been cancelled, or could not be cancelled for some other
    reason. You may need to have additional logic to handle different
    scenarios. The shutdownNow() already handles those scenarios.

Short description and recommendation:-

  • Actually, having a List object itself is not thread-safe

  • Singleton beans are stateless. It should not be maintaining the state
    in the class level. Even if you declare this as prototype bean, it is
    not a good practice to maintain the List (List is not thread safe) of
    futures.

Internally, the executer service implementation classes such as ThreadPoolExecutor, ScheduledThreadPoolExecutor etc. takes care of all the thread safety issues. It uses BlockingQueue to overcome the thread safety issues. Also, it handles exception and different states accordingly. You may need to understand all the internals (i.e. what is happening under the hood) to come up with a good custom solution.

The easy and best way is to use the standard implementations (ThreadPoolExecutor, ScheduledThreadPoolExecutor etc) available in the executor service implementations to avoid any adverse effect (i.e. memory leakage, thread safety issues).

Why executor.isShutdown() returns true when there are threads still running in it's pool?

The calls to shutdownNow() or shutdown() are not blocking. That is what is referred to in the docs.
So if you call shutdown() or shutdownNow(), you get control back immediately, not only after everything has gracefully shut down. If you want to wait for all executors/threads to terminate after the call to shutdown[Now](), you have to call awaitTermination(...), which will block until everything is cleaned up. This is probably what you want. Also see answers to a similar question here: Difference between shutdown and shutdownNow of Executor Service

Don't understand ExecutorService#shutdown

It means that the shutdown method returns immediately. It does not wait for scheduled and already running tasks to complete before returning to its caller. This means that the ExecutorService can still take some time to clean up and terminate itself (which it will eventually do, after all running tasks have completed).

shutdown and awaitTermination which first call have any difference?

You should call shutdown first. Otherwise, you might be waiting for a very long time, since awaitTermination doesn't actually shut down your executor.

If you wanted to wait for tasks to complete, rather than wait for the executor to shut down, then you should use invokeAll.

shutdownNow with executor service

You are right in your assumption, if the Future times out, some hanging threads will remain. Even worse, shutdownNow() will not even shutdown your pool thread (not to mention proprietary API threads). It merely stops accepting new jobs. ExecutorService thread pool will terminate all threads once all running tasks finish.

What you can do is to try canceling the future and interrupting it. First handle InterruptedException inside your future:

class ConnectThread implements Callbale<ApplicationConnection> {

public ApplicationConnection call() {
try {
return prioprietaryApi.connect();
} catch(InterruptedException e) {
prioprietaryApi.cleanUp();
throw e;
}
}

}

Now simply run:

future.cancel(true);

However your proprietary API might not handle InterruptedException (it will not rethrow it from connect(), moreover you might not have access to any cleanUp() method.

In these circumstances just... forget about it. That Future will eventually terminate and clean up after itself, ignoring the fact that you no longer wait for it. Of course this might lead to various scalability issues.

BTW if the only thing you want to achieve is limiting the maximum time given method runs, consider TimeLimiter from guava.

Best way to shutdown ExecutorService in Java

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.


Related Topics



Leave a reply



Submit