[NB.这与
How do I launch a completely independent process from a Java program?有关但不同]
我希望能够从一个“管理器”Java进程中生成外部进程(shell脚本),该进程应该在JVM被杀死时继续运行 – 但是当我杀死父Java程序时,孩子也被杀死了(注意,如果JVM自然退出,行为就不同了).我最简单的测试程序是:
public class Runit { public static void main(String args[]) throws IOException,InterruptedException { Runtime.getRuntime().exec(args[0]); // doesn't work this way either // ProcessBuilder pb = new ProcessBuilder(args[0]); // pb.start(); while (true) { System.out.println("Kill me"); Thread.sleep(2000); } } }
和外部脚本:
#!/bin/sh while [ 1 ] ; do ls sleep 1 done
跑来跑去
java -classpath jar-with-dependencies.jar temp.exec.Runit runit.sh
如果管理器只是退出(即取出Java程序中的“while”循环),那么生成的进程会继续运行,但是当我在Ctrl程序中执行Java程序时,外部程序也会被杀死,这不是我想要的.
我在Ubuntu上使用OpenJDK 1.6.
Edit1:将exec更改为
Runtime.getRuntime().exec("/usr/bin/nohup " + args[0]);
没有帮助.
Edit2:如How to gracefully handle the SIGKILL signal in Java中所述添加关闭挂钩不会阻止Ctrl c传播到子节点.
解决方法
弗拉基米尔给出了我们需要的暗示! (对不起,打败Lukasz吧)
添加另一个脚本spawn_protect.sh
#!/bin/sh LOG=$1 shift nohup $* > $LOG 2>&1 &
并将经理更改为:
public class Runit { public static void main(String args[]) throws IOException,InterruptedException { Runtime.getRuntime().exec(args); while (true) { System.out.println("Kill me"); Thread.sleep(5000); } } }
然后运行:
java -classpath jar-with-dependencies.jar temp.exec.Runit spawn_protect.sh /tmp/runit.log runit.sh
现在runit.sh真的脱离了JVM进程!