【发布时间】:2018-01-15 09:44:39
【问题描述】:
我有一个在 Ubuntu 16.04 LTS 上运行的 Java 应用程序。
当应用程序接收到关闭信号时,会像这样运行关闭序列:
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
shutdown();
}
});
这很好用,但是一旦我尝试调用外部 REST 端点(我正在使用带有 Rx Observables 的 Retrofit),线程就会完全消失在那里,永远不会调用端点,并且不再执行连续的命令。
- 我首先认为 Observables 会是问题所在,并改用了 Retrofit
Call。同样的问题。 - 然后我尝试进行同步调用,而不是异步调用端点。同样的问题。
- 关机时间不是问题。我明确给出了 30 秒。
我认为这与线程有关,例如当一个库在关闭时创建额外的线程时,JVM 似乎会杀死一切。
请任何人阐明或建议我还可以尝试什么。
--
额外信息:
我需要执行长时间运行的清理。问题是我无法确定关闭信号的外观和发生时间,因为 JVM 在 Docker 容器中运行,该容器在 docker stop(主机停止时)首先发送 SIGTERM,然后在超时后(我可以设置,目前为 60 秒)SIGKILL。容器中的 JVM 运行 socket.io,可能会连接数千个客户端。我想使用 60 秒向每个客户端发送 good-bye 并完全断开这些连接,以及从负载均衡器中注销服务器。所以在清理过程中有很多潜在的阻塞操作。
如果 Java 认为清理总是很短,那么 Java 就错了:(
【问题讨论】:
-
Shutdown hooks应该尽快退出,当然不能参与网络操作。请参阅 Javadoc。
标签: java multithreading sigkill sigterm