How to trigger the java shutdown hook for a keep running process?

3.4k Views Asked by At

UPDATED: Now, to get things clear, the situation is: there is a project which is started only by calling the main() function in A class, and in the main() a shutdown hook is added. The A starts many other worker threads and they keep running until the ShutdownHook is executed. My question is how to let the shutdown hook be executed? We used to use kill -9 PID to kill the process. And I am not sure will the shutdown hook be executed with directly kill. I searched a lot, most say with kill -9 the proper shutdown will be ignored? But my colleague said we have been using this way to stop the service for long time...I am now totally confused.

public class A {
//...omitted unrelevant
public static void main(String[] args) {
    final A ctrl = new A(configName, routerId);
    ctrl.startup();
    Runtime.getRuntime().addShutdownHook(new Thread() {
    @Override
            public void run() {
                if (logger.isWarnEnabled()) {
                    logger.warn("Kill signal received, starting shutdown...");
                }
                ctrl.shutdown(); //calling the real shutdown
                if (logger.isWarnEnabled()) {
                    logger.warn("Shutdown done, going down.");
                }

                Set<Thread> threadSet=Thread.getAllStackTraces().keySet();
                String currentThreadName = Thread.currentThread().getName();
                for (Thread thread : threadSet) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Killing : " + thread.getName() + " " + thread.getClass().getName());
                    }
                    if (!thread.getName().equals(currentThreadName)) {
                        thread.stop();
                    }
                }
                System.exit(0);
            }
    }
}

// ...

public void shutdown() {
    if (logger.isDebugEnabled()) {
        logger.debug("requesting shutdown");
    }

    for (Worker w : worker) {
        w.requestShutdown();
    }
    for (Thread t : workerThreads) {
        try {
            t.join();
        } catch (InterruptedException e) {
        }
    }
    if (logger.isDebugEnabled()) {
        logger.debug("shutdown finished");
    }

}}
2

There are 2 best solutions below

0
On BEST ANSWER

Use SIGINT signal, as suggested by kiheru. That is what is sent when you press Ctrl+C.

http://en.wikipedia.org/wiki/Unix_signal

0
On

TLDR: kill -9 is very different from other kill commands. kill -9 is an instruction to the OS to remove a process from the scheduler and take away all of it's memory. Other kill commands pass a signal to the running process and let the process decide how to handle it. That is why kill -9 always works, even when the process is hung.

Extra Detail: On Linux, the regular kill command, with no parameters other than the PID, is a TERM signal, and will cause the shutdown hook to execute.

To demonstrate, consider:

import java.util.concurrent.TimeUnit;

public class RunShutdownHook extends Thread {
    public static void main(String... args) {
        System.out.println(Thread.currentThread().getName() + " - Setting the shutdown hook.");
        final Thread nonDaemonThread = new RunShutdownHook();

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " - Starting shutdown hook.");
                nonDaemonThread.interrupt();

                // Wait to give the interrupted thread a chance to gracefully exit.
                for (int i = 0; i < 10 && nonDaemonThread.isAlive(); i++) {
                    try {
                        TimeUnit.MILLISECONDS.sleep(10);
                    } catch (InterruptedException e) {
                        // We can ignore the InterruptedException because this
                        // thread is about to exit.
                    }
                }
                System.out.println(Thread.currentThread().getName() + " - Finishing shutdown hook.");
            }
        });

        System.out.println(Thread.currentThread().getName() + " - Starting the non-daemon thread.");
        nonDaemonThread.setName("NonDaemonThread");
        nonDaemonThread.start();
        System.out.println(Thread.currentThread().getName() + " - Thread exiting.");
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " - Starting thread.");
        while(!Thread.currentThread().isInterrupted()) {
            System.out.println(Thread.currentThread().getName() + " - Sleeping.");
            try {
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread().getName() + " - Awakened.");
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + " - Interrupted.");
                Thread.currentThread().interrupt();
            }
        }
        System.out.println(Thread.currentThread().getName() + " - Thread exiting.");
    }
}

Interrupted with Ctrl-C:

$ java RunShutdownHook          
main - Setting the shutdown hook.
main - Starting the non-daemon thread.
main - Thread exiting.
NonDaemonThread - Starting thread.
NonDaemonThread - Sleeping.
NonDaemonThread - Awakened.
NonDaemonThread - Sleeping.
^CThread-1 - Starting shutdown hook.
NonDaemonThread - Interrupted.
NonDaemonThread - Thread exiting.
Thread-1 - Finishing shutdown hook.
$ 

Running kill <PID> from another terminal:

$ java RunShutdownHook   
main - Setting the shutdown hook.
main - Starting the non-daemon thread.
main - Thread exiting.
NonDaemonThread - Starting thread.
NonDaemonThread - Sleeping.
NonDaemonThread - Awakened.
NonDaemonThread - Sleeping.
Thread-1 - Starting shutdown hook.
NonDaemonThread - Interrupted.
NonDaemonThread - Thread exiting.
Thread-1 - Finishing shutdown hook.
$ 

Running kill -9 <PID> from another terminal:

$ java RunShutdownHook
main - Setting the shutdown hook.
main - Starting the non-daemon thread.
main - Thread exiting.
NonDaemonThread - Starting thread.
NonDaemonThread - Sleeping.
NonDaemonThread - Awakened.
NonDaemonThread - Sleeping.
zsh: killed     java RunShutdownHook
$ 

kill -9 does not activate the shutdown hook.