0

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?

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • It appears @Izik Golan has a solution to your problem. If that works for you, do +1 and accept his answer. – zEro Jul 07 '13 at 21:44

2 Answers2

2

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

Izik Golan
  • 802
  • 6
  • 4
1

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.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Thanks @Stephen C (+1) - so whats the solution here: make `Timer` a daemon? If so, how? –  Jul 05 '13 at 03:34
  • @TicketMonster Use [`Timer(true)`](http://docs.oracle.com/javase/7/docs/api/java/util/Timer.html#Timer(boolean)) to create a daemon `Timer`. – Jeffrey Jul 05 '13 at 03:43
  • Thanks again @Stephen C, however setting `Timer(true)` does not cause the `executor` to shudown when the main thread finishes... –  Jul 05 '13 at 17:37
  • @TicketMonster - Are you saying that the symptoms are the same with `Timer(true)`? – Stephen C Jul 05 '13 at 22:37