8

I am trying to get a shutdown hook to work on my ubuntu server, however I seem to have an issue with more than one thread. Using the a basic ShutdownHook, the following bit of code does work when I kill the process using kill <PID>, meaning the shutdown behavior is activated.

public static void main(String[] args) {
    ShutdownHook shutDown = new ShutdownHook();
    shutDown.attachShutDownHook();

    while(true){}
}

however this same code with an additional thread does not

public static void main(String[] args) {
    ShutdownHook shutDown = new ShutdownHook();
    shutDown.attachShutDownHook();

    (new Thread() {
        public void run() {
            while ( true ) {}
        }
    }).start();

    while(true){}
}

Any ideas?

class ShutdownHook {

    ShutdownHook() {
    }

    public void attachShutDownHook() {

            Runtime.getRuntime().addShutdownHook(new Thread() {
                    @Override
                    public void run() {
                            System.out.println("Shut down hook activating");
                    }
            });
            System.out.println("Shut Down Hook Attached.");

    }
}
Reese
  • 173
  • 3
  • 7
  • What is the behavior with the second thread? Does the application stop without calling the shutdown behavior? Also you say "kill the process". What do you mean by that? How are you terminating it? – Gray Oct 31 '12 at 13:18
  • The second thread is just an example of a live thread. In my actual example it is listening for connections on a port, and remains alive throughout the lifetime of the program. I'm terminating the process with `kill `. The second program above does not work as is, so there is something I am missing regarding more than one thread – Reese Oct 31 '12 at 13:22
  • Try running `jstack ` on after you've called `kill` to see what threads are still running. – SimonC Oct 31 '12 at 13:28
  • Once I've killed the process, I can't run jstack, it just says No such process – Reese Oct 31 '12 at 13:44
  • The problem is: the process is killed but without calling shutdown hook, post the code of the shutdown hook please, and add a System.err.println() at first line of it. – Aubin Oct 31 '12 at 13:49
  • 1
    You must have something else that's not included here. I've just tried your example (with the additional thread) and it all works as expected: ` $ java ShutdownHook Shut Down Hook Attached. Shut down hook activating $ java ShutdownHook & [1] 4879 $ Shut Down Hook Attached. $ kill 4879 Shut down hook activating $ ` – SimonC Nov 01 '12 at 05:08
  • I've seen this behaviour in my more complex application, but can't reproduce it with your barebones example. But in my case, it only happens if i really shut down, that is press the power button, not send the signals. Also it is strange that way because the shut down doesn't wait, like /etc/init.d/sendsigs says it should for hanging processes (up to 10 seconds) but the shutdown hook is never run (because it is logging to file). I'm actually suspecting a signal handling bug on the JVM or something killing java with SIGKILL before SIGTERM. The bug doesn't exist in windows. – i30817 Mar 01 '14 at 19:39

3 Answers3

3

The JVM won't exit while there are still non-daemon threads running. Try calling setDaemon(true) on your new thread.

SimonC
  • 6,590
  • 1
  • 23
  • 40
1

To take an example from a project of my own;

My core class spawns a whole bunch of worker threads, the workers run transactions that must complete.

In the core class I have;

Runtime.getRuntime().addShutdownHook(new ShutdownCleanup());

Which looks something like;

public final class ShutdownCleanup extends Thread() {
    public void run() {
        log("waiting for worker threads to finish...");
        while(WorkerThread.transactionInProgress()) {
            Thread.sleep(1000);
        }
        //close various sockets and resources
    }
}

The moment I hit Ctrl+C in the terminal, the log message appears. So the shutdown hook activates immediately, it isn't something that runs once the program is ready to die, rather it runs as soon as the close or kill request is received.

For this reason I believe what others have said about shutdown hooks never being called while there is still a thread alive is false. What would be the point of a shutdown hook that only activated once everything has died anyway?

It might be that you're using a hard kill, such as -9. Have you tried a normal shutdown with Ctrl+C or SIGINT?

lynks
  • 5,599
  • 6
  • 23
  • 42
  • Yes I've tried `kill ` with no arguments, and `CTRL+C`. Both work in the first, single threaded example, and neither works as soon as I have more than one thread. Perhaps something I am missing setting up my thread? – Reese Oct 31 '12 at 13:48
  • Have you tried using the `Runtime` method above? I have no idea what difference it would make, but maybe you're attaching a hook to one thread rather than the JVM...if that's possible. – lynks Oct 31 '12 at 13:49
  • I'm using Runtime. I updated my original question to show the ShutdownHook itself – Reese Oct 31 '12 at 13:56
  • Then I really don't know. My working example seems to be the same as yours. I have 16 worker threads running, they `implement Runnable` rather than `extend Thread` but that should make no difference. Do you have a `System.out.println` or similar at the first line of your `run()` method in the shutdown hook? It *must* be running! – lynks Oct 31 '12 at 14:23
0

java.lang.Runtime.addShutdownHook( Thread ) registers a new virtual-machine shutdown hook:

The Java virtual machine shuts down in response to two kinds of events:

  • The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or

  • The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.

Your code runs indefinitely so the shutdown hook will never be called.

[After your edit]

Which kill do you use?

kill -9 is non trappable

kill -2 may be used to emulate a ctrl-c (SIGINT)

Aubin
  • 14,617
  • 9
  • 61
  • 84
  • I'm using `kill ` with no extra arguments. It should be trappable, and in fact does work in the one thread scenario – Reese Oct 31 '12 at 13:46