当程序收到终止信号时,如何处理清除?例如,我连接的一个应用程序希望任何第三方应用程序(我的应用程序)发送 finish 注销时的命令。寄那封信最好说什么 finish 当我的应用程序被 kill -9 ?编辑1:无法捕获kill-9。谢谢你们纠正我。编辑2:我想这种情况应该是当一个调用just kill时,这与ctrl-c是一样的
finish
kill -9
wbgh16ku1#
有一种方法可以对kill-9做出React:那就是有一个单独的进程来监视被kill的进程,并在必要时进行清理。这可能会涉及ipc,并且需要大量的工作,您仍然可以通过同时终止两个进程来覆盖它。我想在大多数情况下不值得麻烦。无论是谁用-9杀死一个进程,理论上都应该知道他/她在做什么,这可能会使事情处于不一致的状态。
xqk2d5yq2#
你可以用 Runtime.getRuntime().addShutdownHook(...) ,但不能保证它在任何情况下都会被调用。
Runtime.getRuntime().addShutdownHook(...)
sd2nnvve3#
在某些jvm中,有一些方法可以处理您自己的信号——例如,请参阅这篇关于热点jvm的文章。利用太阳内部 sun.misc.Signal.handle(Signal, SignalHandler) 方法调用您还可以注册一个信号处理程序,但可能不适用于 INT 或者 TERM 因为它们被jvm使用。为了能够处理任何信号,您必须跳出jvm进入操作系统领域。我通常(例如)检测异常终止的方法是在perl脚本中启动jvm,但是让脚本使用 waitpid 系统调用。然后,每当jvm退出时,就会通知我它退出的原因,并可以采取必要的操作。
sun.misc.Signal.handle(Signal, SignalHandler)
INT
TERM
waitpid
rpppsulh4#
我希望jvm会优雅地中断( thread.interrupt() )应用程序创建的所有正在运行的线程,至少对于信号 SIGINT (kill -2) 以及 SIGTERM (kill -15) .这样,信号将被转发给他们,允许以标准方式优雅地取消线程和完成资源。但事实并非如此(至少在我的jvm实现中: Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode) .正如其他用户所评论的,shutdown钩子的使用似乎是强制性的。那么,我该怎么处理呢?首先,我并不关心所有的程序,只关心那些我想跟踪用户取消和意外结束的程序。例如,假设您的java程序是一个由其他人管理的进程。您可能需要区分它是否被优雅地终止( SIGTERM 或者发生了关闭(以便在启动时自动重新启动作业)。作为基础,我总是让我的长时间运行的线程周期性地意识到中断状态,并抛出一个 InterruptedException 如果他们打断了。这使得执行最终化以开发人员控制的方式进行(也产生与标准阻塞操作相同的结果)。然后,在线程堆栈的顶层, InterruptedException 捕获并执行适当的清理。这些线程被编码为知道如何响应中断请求。高内聚性设计。因此,在这些情况下,我添加了一个shutdown hook,它完成了我认为jvm在默认情况下应该做的事情:中断我的应用程序创建的所有仍在运行的非守护进程线程:
thread.interrupt()
SIGINT (kill -2)
SIGTERM (kill -15)
Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
SIGTERM
InterruptedException
Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { System.out.println("Interrupting threads"); Set<Thread> runningThreads = Thread.getAllStackTraces().keySet(); for (Thread th : runningThreads) { if (th != Thread.currentThread() && !th.isDaemon() && th.getClass().getName().startsWith("org.brutusin")) { System.out.println("Interrupting '" + th.getClass() + "' termination"); th.interrupt(); } } for (Thread th : runningThreads) { try { if (th != Thread.currentThread() && !th.isDaemon() && th.isInterrupted()) { System.out.println("Waiting '" + th.getName() + "' termination"); th.join(); } } catch (InterruptedException ex) { System.out.println("Shutdown interrupted"); } } System.out.println("Shutdown finished"); } });
在github完成测试应用程序:https://github.com/idelvall/kill-test
kpbpu0085#
任何语言的程序都不可能处理sigkill。因此,即使程序有缺陷或恶意,也始终可以终止程序。但是sigkill并不是终止程序的唯一方法。另一种是使用sigterm。程序可以处理这个信号。程序应该通过控制但快速的关机来处理信号。当计算机关闭时,关闭进程的最后一个阶段会向每个剩余进程发送一个sigterm,给这些进程几秒钟的宽限期,然后向它们发送一个sigkill。处理这件事的方法除了 kill -9 就是注册一个关机钩子。如果您可以使用(sigterm) kill -15 关闭挂钩可以工作(信号) kill -2 不会导致程序正常退出并运行关闭挂钩。注册新的虚拟机关闭挂钩。java虚拟机将关闭,以响应两种事件:当最后一个非守护进程线程退出或调用exit(相当于system.exit)方法时,程序正常退出,或者响应用户中断(如键入^c)或系统范围的事件(如用户注销或系统关闭),虚拟机被终止。我在OSX10.6.3和其他平台上尝试了以下测试程序 kill -9 它没有像预期的那样运行关闭挂钩。在 kill -15 它确实每次都运行关闭挂钩。
kill -15
kill -2
public class TestShutdownHook { public static void main(String[] args) throws InterruptedException { Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { System.out.println("Shutdown hook ran!"); } }); while (true) { Thread.sleep(1000); } } }
没有任何方法可以真正优雅地处理 kill -9 在任何程序中。在极少数情况下,虚拟机可能会中止,即在未完全关闭的情况下停止运行。当虚拟机在外部终止时会发生这种情况,例如在unix上使用sigkill信号或在microsoft windows上使用terminateprocess调用。唯一的解决问题的方法 kill -9 是让另一个监视程序监视您的主程序离开或使用 Package 器脚本。您可以使用轮询 ps 命令在列表中查找您的程序,并在它消失时采取相应的行动。
ps
# !/usr/bin/env bash java TestShutdownHook wait # notify your other app that you quit echo "TestShutdownHook quit"
5条答案
按热度按时间wbgh16ku1#
有一种方法可以对kill-9做出React:那就是有一个单独的进程来监视被kill的进程,并在必要时进行清理。这可能会涉及ipc,并且需要大量的工作,您仍然可以通过同时终止两个进程来覆盖它。我想在大多数情况下不值得麻烦。
无论是谁用-9杀死一个进程,理论上都应该知道他/她在做什么,这可能会使事情处于不一致的状态。
xqk2d5yq2#
你可以用
Runtime.getRuntime().addShutdownHook(...)
,但不能保证它在任何情况下都会被调用。sd2nnvve3#
在某些jvm中,有一些方法可以处理您自己的信号——例如,请参阅这篇关于热点jvm的文章。
利用太阳内部
sun.misc.Signal.handle(Signal, SignalHandler)
方法调用您还可以注册一个信号处理程序,但可能不适用于INT
或者TERM
因为它们被jvm使用。为了能够处理任何信号,您必须跳出jvm进入操作系统领域。
我通常(例如)检测异常终止的方法是在perl脚本中启动jvm,但是让脚本使用
waitpid
系统调用。然后,每当jvm退出时,就会通知我它退出的原因,并可以采取必要的操作。
rpppsulh4#
我希望jvm会优雅地中断(
thread.interrupt()
)应用程序创建的所有正在运行的线程,至少对于信号SIGINT (kill -2)
以及SIGTERM (kill -15)
.这样,信号将被转发给他们,允许以标准方式优雅地取消线程和完成资源。
但事实并非如此(至少在我的jvm实现中:
Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
.正如其他用户所评论的,shutdown钩子的使用似乎是强制性的。
那么,我该怎么处理呢?
首先,我并不关心所有的程序,只关心那些我想跟踪用户取消和意外结束的程序。例如,假设您的java程序是一个由其他人管理的进程。您可能需要区分它是否被优雅地终止(
SIGTERM
或者发生了关闭(以便在启动时自动重新启动作业)。作为基础,我总是让我的长时间运行的线程周期性地意识到中断状态,并抛出一个
InterruptedException
如果他们打断了。这使得执行最终化以开发人员控制的方式进行(也产生与标准阻塞操作相同的结果)。然后,在线程堆栈的顶层,InterruptedException
捕获并执行适当的清理。这些线程被编码为知道如何响应中断请求。高内聚性设计。因此,在这些情况下,我添加了一个shutdown hook,它完成了我认为jvm在默认情况下应该做的事情:中断我的应用程序创建的所有仍在运行的非守护进程线程:
在github完成测试应用程序:https://github.com/idelvall/kill-test
kpbpu0085#
任何语言的程序都不可能处理sigkill。因此,即使程序有缺陷或恶意,也始终可以终止程序。但是sigkill并不是终止程序的唯一方法。另一种是使用sigterm。程序可以处理这个信号。程序应该通过控制但快速的关机来处理信号。当计算机关闭时,关闭进程的最后一个阶段会向每个剩余进程发送一个sigterm,给这些进程几秒钟的宽限期,然后向它们发送一个sigkill。
处理这件事的方法除了
kill -9
就是注册一个关机钩子。如果您可以使用(sigterm)kill -15
关闭挂钩可以工作(信号)kill -2
不会导致程序正常退出并运行关闭挂钩。注册新的虚拟机关闭挂钩。
java虚拟机将关闭,以响应两种事件:
当最后一个非守护进程线程退出或调用exit(相当于system.exit)方法时,程序正常退出,或者
响应用户中断(如键入^c)或系统范围的事件(如用户注销或系统关闭),虚拟机被终止。
我在OSX10.6.3和其他平台上尝试了以下测试程序
kill -9
它没有像预期的那样运行关闭挂钩。在kill -15
它确实每次都运行关闭挂钩。没有任何方法可以真正优雅地处理
kill -9
在任何程序中。在极少数情况下,虚拟机可能会中止,即在未完全关闭的情况下停止运行。当虚拟机在外部终止时会发生这种情况,例如在unix上使用sigkill信号或在microsoft windows上使用terminateprocess调用。
唯一的解决问题的方法
kill -9
是让另一个监视程序监视您的主程序离开或使用 Package 器脚本。您可以使用轮询ps
命令在列表中查找您的程序,并在它消失时采取相应的行动。