56

Whenever I call shutdownNow() or shutdown() it doesn't shut down. I read of a few threads where it said that shutting down is not guaranteed - can someone provide me a good way of doing it?

rosesr
  • 749
  • 1
  • 7
  • 10

3 Answers3

93

The typical pattern is:

executorService.shutdownNow();
executorService.awaitTermination();

When calling shutdownNow, the executor will (generally) try to interrupt the threads that it manages. To make the shutdown graceful, you need to catch the interrupted exception in the threads or check the interrupted status. If you don't your threads will run forever and your executor will never be able to shutdown. This is because the interruption of threads in Java is a collaborative process (i.e. the interrupted code must do something when asked to stop, not the interrupting code).

For example, the following code prints Exiting normally.... But if you comment out the line if (Thread.currentThread().isInterrupted()) break;, it will print Still waiting... because the threads within the executor are still running.

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()) break;
            }
        }
    });

    executor.shutdownNow();
    if (!executor.awaitTermination(100, TimeUnit.MICROSECONDS)) {
        System.out.println("Still waiting...");
        System.exit(0);
    }
    System.out.println("Exiting normally...");
}

Alternatively, it could be written with an InterruptedException like this:

public static void main(String args[]) throws InterruptedException {
    ExecutorService executor = Executors.newFixedThreadPool(1);
    executor.submit(new Runnable() {

        @Override
        public void run() {
            try {
                while (true) {Thread.sleep(10);}
            } catch (InterruptedException e) {
                //ok let's get out of here
            }
        }
    });

    executor.shutdownNow();
    if (!executor.awaitTermination(100, TimeUnit.MICROSECONDS)) {
        System.out.println("Still waiting...");
        System.exit(0);
    }
    System.out.println("Exiting normally...");
}
assylias
  • 321,522
  • 82
  • 660
  • 783
34

The best way is what we actually have in the javadoc which is:

The following method shuts down an ExecutorService in two phases, first by calling shutdown to reject incoming tasks, and then calling shutdownNow, if necessary, to cancel any lingering tasks:

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();
    }
}
Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
1

Java 19 makes ExecutorService implement AutoCloseable, meaning it shuts down when exiting a try-with-resources block:

try (ExecutorService e = Executors.newFixedThreadPool(2)) {
   e.submit(task1);
   e.submit(task2);
} // blocks and waits

This is a structured concurrency approach developed as part of Project Loom, which is incubating in Java 19. As of July 2022, Java 19 is not officially released but early access builds are available.

hertzsprung
  • 9,445
  • 4
  • 42
  • 77
  • The JDK implementation is good reference, but week in mind the close methods wait for all task completion, and `awaitTermination` is waiting for 1 day (repetitively). – bric3 Oct 05 '22 at 10:51
  • I think this [answer](https://stackoverflow.com/a/37443866/48136) is the proper one if you want to close in a timely fashion. – bric3 Oct 05 '22 at 10:57