简体   繁体   中英

Shutdown hook is not killing executor

I have the following code:

public class Driver {
    private ExecutorService executor = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        Driver d = new Driver();
        d.run();
    }

    private void run() {
        final Timer timer = new Timer();
        final TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("Task is running!");
            }
        };

        Runnable worker = new Runnable() {
            @Override
            public void run() {
                timer.scheduleAtFixedRate(task, new Date(), 5 * 1000);
            }
        };

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.out.println("Shutdown hook is being invoked!");

                try {
                    if(executor.awaitTermination(20, TimeUnit.SECONDS))
                        System.out.println("All workers shutdown properly.");
                    else {
                        System.out.println(String.format("Maximum time limit of %s reached " +
                                "when trying to shut down workers. Forcing shutdown.", 20));
                        executor.shutdownNow();
                    }
                } catch (InterruptedException interrupt) {
                    System.out.println("Shutdown hook interrupted by exception: " +
                            interrupt.getMessage());
                }

                System.out.println("Shutdown hook is finished!");
            }
        });

        executor.submit(worker);

        System.out.println("Initializing shutdown...");
    }
}

When this runs I get the following console output:

Initializing shutdown...
Task is running!
Task is running!
Task is running!
Task is running!
Task is running!
Task is running!
Task is running!
... (this keeps going non-stop)

When I run this, the application never terminates. Instead, every 5 seconds, I see a new println of "Task is running!". I would have expected the main thread to reach the end of the main method, print "Initializing shutdown...", invoked the added shutdown hook, killed the executor, and finally print out "Shutdown hook is finished!".

Instead, "Task is running" just keeps getting printed and the program never terminates. What's going on here?

I am no expert but AFAIK you must have all non-Daemon threads terminated in order for the shutdown hook to “kick in”. In the original example you have 3 non-Daemon:

  1. The thread of “Main” – this is the only non-Daemon you want here..
  2. The thread that runs the “TimerTask” – it is created by the “Timer” and you covered it by fixing to Timer(true)
  3. The thread that runs the “worker” – it is created by the “executor” and in order for the “executor” to create Daemon threads you should create a ThreadFactory . (at least this is the way I know; there might be other ways...)

So I think what you should do is to create a ThreadFactory and use it when initializing the “executor”.

Create a class that will be the ThreadFactory :

private class WorkerThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r, "Worker");
        t.setDaemon(true);
        return t;
    }
}

-- the important line is the setDaemon of course :)

Pass an instance of it as a parameter to the newCachedThreadPool method:

private ExecutorService executor = Executors.newCachedThreadPool(new WorkerThreadFactory());

Applying these 2 changes did the trick for me and I got to:

Maximum time limit of 20 reached when trying to shut down workers. Forcing shutdown.
Shutdown hook is finished!

Hope it helps,
Izik

golan2@hotmail.com

It is not shutting down because Timer() creates and starts a non-daemon thread ... which is then never stopped.

There are two things that can cause the JVM to shutdown of its own accord:

  • A call to System.exit() (or Runtime.halt() )
  • The termination of the last remaining non-daemon thread.

Since you have created a second non-daemon thread (in addition to the thread that is running main() ) the second condition won't be met.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM