如何在Java中优雅地处理SIGKILL信号
当程序收到终止信号时如何处理清理?
例如,我连接的一个应用程序希望任何第三方应用程序(我的应用程序)在注销时发送 finish
命令。当我的应用程序被 kill -9
销毁时,发送 finish
命令的最佳说法是什么?
编辑1:kill -9无法被捕获。谢谢你们纠正我。
编辑2:我想这种情况是当一个人调用kill时,它与ctrl-c相同
How do you handle clean up when the program receives a kill signal?
For instance, there is an application I connect to that wants any third party app (my app) to send a finish
command when logging out. What is the best say to send that finish
command when my app has been destroyed with a kill -9
?
edit 1: kill -9 cannot be captured. Thank you guys for correcting me.
edit 2: I guess this case would be when the one calls just kill which is the same as ctrl-c
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
对于任何语言的任何程序来说,处理 SIGKILL 都是不可能的。这样,即使程序有错误或恶意,也始终可以终止程序。但 SIGKILL 并不是终止程序的唯一方法。另一种是使用 SIGTERM。程序可以处理该信号。程序应该通过执行受控但快速的关闭来处理信号。当计算机关闭时,关闭过程的最后阶段会向每个剩余进程发送一个 SIGTERM,给这些进程几秒钟的宽限期,然后向它们发送一个 SIGKILL。
对于除
kill -9
之外的任何其他处理此问题的方法是注册一个 关闭 钩子。如果您可以使用 (SIGTERM)kill -15
关闭挂钩将起作用。 (SIGINT)kill -2
确实导致程序正常退出并运行关闭挂钩。我在 OSX 10.6.3 上尝试了以下测试程序,在
kill -9
上,它确实没有按照预期运行关闭挂钩。在kill -15
上,它确实每次都会运行关闭挂钩。在任何程序中都没有任何方法可以真正优雅地处理
kill -9
。处理
kill -9
的唯一真正选择是让另一个观察程序监视您的主程序是否消失或使用包装脚本。您可以使用 shell 脚本来完成此操作,该脚本轮询 ps 命令以在列表中查找您的程序,并在它消失时采取相应的操作。It is impossible for any program, in any language, to handle a SIGKILL. This is so it is always possible to terminate a program, even if the program is buggy or malicious. But SIGKILL is not the only means for terminating a program. The other is to use a SIGTERM. Programs can handle that signal. The program should handle the signal by doing a controlled, but rapid, shutdown. When a computer shuts down, the final stage of the shutdown process sends every remaining process a SIGTERM, gives those processes a few seconds grace, then sends them a SIGKILL.
The way to handle this for anything other than
kill -9
would be to register a shutdown hook. If you can use (SIGTERM)kill -15
the shutdown hook will work. (SIGINT)kill -2
DOES cause the program to gracefully exit and run the shutdown hooks.I tried the following test program on OSX 10.6.3 and on
kill -9
it did NOT run the shutdown hook, as expected. On akill -15
it DOES run the shutdown hook every time.There isn't any way to really gracefully handle a
kill -9
in any program.The only real option to handle a
kill -9
is to have another watcher program watch for your main program to go away or use a wrapper script. You could do with this with a shell script that polled theps
command looking for your program in the list and act accordingly when it disappeared.我希望 JVM 能够优雅地中断 (
thread.interrupt()
) 应用程序创建的所有正在运行的线程,至少对于信号SIGINT (kill -2)
和SIGTERM(kill -15)
。这样,信号将被转发给它们,从而允许在 标准方式。
但事实并非如此(至少在我的 JVM 实现中:
Java(TM) SE 运行时环境(内部版本 1.8.0_25-b17)、Java HotSpot(TM) 64 位服务器 VM (版本 25.25-b02,混合模式)
正如其他用户评论的那样,关闭挂钩的使用似乎是强制性的,
要如何处理它?
那么,我首先 在所有程序中,仅在那些我想要跟踪用户取消和意外结束的程序中,例如,假设您的 java 程序是由其他程序管理的进程(< code>SIGTERM 来自管理器进程)或发生关闭(为了在启动时自动重新启动作业),
我总是让长时间运行的线程定期了解中断状态并抛出 < code>InterruptedException 如果它们被中断,这将允许以开发人员控制的方式完成执行(也产生与标准阻塞操作相同的结果)。然后,在线程堆栈的顶层,捕获 InterruptedException 并执行适当的清理。这些线程被编码为知道如何响应中断请求。高凝聚力设计。
因此,在这些情况下,我添加了一个关闭挂钩,它执行我认为 JVM 默认情况下应该执行的操作:中断由我的应用程序创建的仍在运行的所有非守护线程:
github 上的完整测试应用程序:https://github.com/idelvall/kill-test
I would expect that the JVM gracefully interrupts (
thread.interrupt()
) all the running threads created by the application, at least for signalsSIGINT (kill -2)
andSIGTERM (kill -15)
.This way, the signal will be forwarded to them, allowing a gracefully thread cancellation and resource finalization in the standard ways.
But this is not the case (at least in my JVM implementation:
Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
.As other users commented, the usage of shutdown hooks seems mandatory.
So, how do I would handle it?
Well first, I do not care about it in all programs, only in those where I want to keep track of user cancellations and unexpected ends. For example, imagine that your java program is a process managed by other. You may want to differentiate whether it has been terminated gracefully (
SIGTERM
from the manager process) or a shutdown has occurred (in order to relaunch automatically the job on startup).As a basis, I always make my long-running threads periodically aware of interrupted status and throw an
InterruptedException
if they interrupted. This enables execution finalization in way controlled by the developer (also producing the same outcome as standard blocking operations). Then, at the top level of the thread stack,InterruptedException
is captured and appropriate clean-up performed. These threads are coded to known how to respond to an interruption request. High cohesion design.So, in these cases, I add a shutdown hook, that does what I think the JVM should do by default: interrupt all the non-daemon threads created by my application that are still running:
Complete test application at github: https://github.com/idelvall/kill-test
有一些方法可以在某些 JVM 中处理您自己的信号 - 请参阅这篇关于 HotSpot JVM 的文章 为例。
通过使用 Sun 内部
sun.misc.Signal.handle(Signal, SignalHandler)
方法调用,您还可以注册信号处理程序,但可能不适用于像INT
这样的信号或TERM
,因为它们被 JVM 使用。为了能够处理任何信号,您必须跳出 JVM 并进入操作系统领域。
我通常(例如)检测异常终止的做法是在 Perl 脚本内启动 JVM,但让脚本使用
waitpid
系统调用等待 JVM。然后,每当 JVM 退出时,我都会收到通知以及退出原因,并可以采取必要的操作。
There are ways to handle your own signals in certain JVMs -- see this article about the HotSpot JVM for example.
By using the Sun internal
sun.misc.Signal.handle(Signal, SignalHandler)
method call you are also able to register a signal handler, but probably not for signals likeINT
orTERM
as they are used by the JVM.To be able to handle any signal you would have to jump out of the JVM and into Operating System territory.
What I generally do to (for instance) detect abnormal termination is to launch my JVM inside a Perl script, but have the script wait for the JVM using the
waitpid
system call.I am then informed whenever the JVM exits, and why it exited, and can take the necessary action.
参考 https://aws.amazon.com/blogs/containers/graceful -shutdowns-with-ecs/
Reference https://aws.amazon.com/blogs/containers/graceful-shutdowns-with-ecs/
您可以使用 Runtime.getRuntime().addShutdownHook(...),但不能保证它在任何情况下都会被调用。
You can use
Runtime.getRuntime().addShutdownHook(...)
, but you cannot be guaranteed that it will be called in any case.有一种方法可以对kill -9做出反应:那就是有一个单独的进程来监视被杀死的进程,并在必要时进行清理。这可能会涉及 IPC,并且会是相当多的工作,您仍然可以通过同时终止两个进程来覆盖它。我认为在大多数情况下这是不值得的。
理论上,无论谁用 -9 杀死一个进程,都应该知道他/她在做什么,并且这可能会使事情处于不一致的状态。
There is one way to react to a kill -9: that is to have a separate process that monitors the process being killed and cleans up after it if necessary. This would probably involve IPC and would be quite a bit of work, and you can still override it by killing both processes at the same time. I assume it will not be worth the trouble in most cases.
Whoever kills a process with -9 should theoretically know what he/she is doing and that it may leave things in an inconsistent state.