使用ProcessBuilder
,我一直在尝试创建一个独立的进程,当JVM终止时不会终止,但似乎没有任何工作。
我已经尝试过/usr/bin/nohup commands
,但是当启动它的JVM终止时,它似乎仍然会终止。有没有办法在Java中实现这一目标?
首先,我们首先要编写一个测试脚本来验证您所看到的内容:
$ cat /tmp/test.sh
#!/bin/bash
for sig in SIGINT SIGTERM SIGHUP; do
trap "echo Caught $sig" $sig
done
echo Traps registered, sleeping
sleep 10
echo Done sleeping, exiting
当我通过以下方式调用时:
new ProcessBuilder("/tmp/test.sh").inheritIO().start().waitFor(1, TimeUnit.SECONDS);
我看到Java进程在1秒后终止(自waitFor()
超时),但子进程继续运行(在JVM退出后,Done sleeping
消息被打印到控制台)。这与this question中讨论的内容排列在一起。
所以我建议做的第一件事是验证你最初假设子进程实际上被杀死了;或许还有别的东西会因为另一个原因导致它死亡。使用.inheritIO()
可以帮助调试,以防子进程生成您没有看到的错误消息。
所有这一切,nohup
可能不是你想要的,就像'那个其他人'的笔记; nohup
只会导致一个进程忽略SIGHUP
,它仍然会尊重其他信号,例如SIGINT
和SIGTERM
(例如Process.destroy()
sends a SIGTERM
)。有关更多信息,请参阅this question。
与编程中的所有问题一样,引入更多层可能会有所帮助:)
创建一个处理所需的disowning逻辑的shell脚本,例如:
$ cat start-and-disconnect.sh
#!/bin/bash
# obviously tweak this as necessary to get the behavior you want,
# such as redirecting output or using disown instead of nohup
nohup "$@" &
这里的优点是Bash(或您喜欢的任何shell)具有比Java更好的进程管理控制,现在您可以单独测试它,而无需编译和运行Java应用程序。
一旦您对脚本感到满意,您的Java代码就会变成:
new ProcessBuilder("/path/to/start-and-disconnect.sh", "/path/to/your_binary.sh")
.inheritIO().start().waitFor();
您可以安全地.waitFor()
完成调用,因为start-and-disconnect.sh
将在启动其子进程后退出。