【问题标题】:How to trigger the java shutdown hook for a keep running process?如何触发 java 关闭钩子以继续运行进程?
【发布时间】:2015-01-26 12:19:08
【问题描述】:

更新: 现在,为了弄清楚,情况是:有一个项目只通过调用A类中的main()函数来启动,并且在main()中添加了一个关闭钩子。 A 启动了许多其他工作线程,并且它们一直运行直到 ShutdownHook 被执行。 我的问题是如何让关闭钩子被执行?我们曾经使用 kill -9 PID 来杀死进程。而且我不确定是否会直接使用 kill 执行关闭挂钩。 我搜索了很多,大多数人说用 kill -9 正确关闭会被忽略吗?但是我的同事说我们一直在使用这种方式来停止服务......我现在完全糊涂了。

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");
    }

}}

【问题讨论】:

  • kill -9 是唯一一个不能被进程拦截的 Unix 信号,因此不会触发任何关闭挂钩。从描述中不清楚你在问什么,也许如果你发布你的代码,你的问题会变得更清楚。
  • 我已经更新了我的问题。
  • SIGKILL 杀死的进程(这是kill -9 所做的)将没有任何机会运行任何关闭活动。信号无法被捕获,进程将被简单终止。如果您需要“更柔和”的终止信号,请使用专用的终止信号(SIGINTSIGTERM)。
  • @kiheru 好的,那你知道如何让它执行正确的关机而不更改原始代码吗?
  • 根据docs,'如果虚拟机中止,则不能保证是否会运行任何关闭挂钩。'

标签: java tomcat process pid shutdown


【解决方案1】:

TLDR:kill -9 与其他 kill 命令非常不同。 kill -9 是给操作系统的一条指令,用于从调度程序中删除一个进程并带走它的所有内存。其他kill 命令将信号传递给正在运行的进程,让进程决定如何处理它。这就是为什么kill -9 总是有效的原因,即使进程挂起。

额外细节:在 Linux 上,常规的kill 命令,除了 PID 之外没有其他参数,是一个 TERM 信号,将导致关闭挂钩执行。

为了演示,考虑:

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.");
    }
}

被 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.
$ 

从另一个终端运行kill &lt;PID&gt;

$ 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.
$ 

从另一个终端运行kill -9 &lt;PID&gt;

$ 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 不会激活关机钩子。

【讨论】:

    【解决方案2】:

    按照 kiheru 的建议,使用 SIGINT 信号。这就是你按下 Ctrl+C 时发送的内容。

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

    【讨论】:

      猜你喜欢
      • 2019-08-05
      • 1970-01-01
      • 2014-09-14
      • 1970-01-01
      • 1970-01-01
      • 2019-09-24
      • 2014-09-02
      • 2014-07-31
      相关资源
      最近更新 更多