How to prevent ctrl+c killing spawned processes in Java

[NB. This is related to How do I launch a completely independent process from a Java program? but different]

I want to be able to spawn external processes (shell scripts) from a "manager" Java process that should keep running when the JVM is killed - but it seems that when I kill the parent Java program the child is killed too (note, the behaviour is different if the JVM exits naturally). The simplest test program I have is:

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);
        }
    }
}

and external script:

#!/bin/sh

while [ 1 ] ; do 
    ls
    sleep 1
done

run as

java -classpath jar-with-dependencies.jar temp.exec.Runit runit.sh

If the manager simply exits (ie take out the "while" loop in the Java program) then the spawned process keeps running, but when I Ctrl+c the Java program the external program is killed too which is not what I want.

I'm using OpenJDK 1.6 on Ubuntu.

Edit1: Changing the exec to

Runtime.getRuntime().exec("/usr/bin/nohup " +  args[0]);

doesn't help.

Edit2: Adding a shutdown hook as described in How to gracefully handle the SIGKILL signal in Java doesn't stop the Ctrl+c being propagated to the child.


Vladimir gave the hint we needed! (Sorry, beat Lukasz to it)

Add another script spawn_protect.sh

#!/bin/sh

LOG=$1
shift 

nohup $* > $LOG 2>&1  &

And change the manager to:

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);
        }
    }
}

Then run as:

java -classpath jar-with-dependencies.jar temp.exec.Runit spawn_protect.sh /tmp/runit.log runit.sh

Now runit.sh is really detached from the JVM process!


In Linux, if you start another process, it is your child and you are his parent. If parent gets killed, all children get killed, and their children too (what a terrible atrocity).

What you need, is to start a process that won't be killed when you exit your program. So, you need to give birth to not your own child. The methods to do that are described for example here: Linux: Prevent a background process from being stopped after closing SSH client for example use screen utility.


You've got to make it a daemon. Don't be afraid it's not a horror movie. Simply you'll need to detach your processes from controlling terminal session. I've always do it in a oposite way: shell script that launches Java.

Here is an explanation:

http://en.wikipedia.org/wiki/Daemon_(computing)

You can also you "jvm shutdown hooks", but they will not work in some situations.

链接地址: http://www.djcxy.com/p/80646.html

上一篇: Haskell在理论上不应该这样的情况下陷入僵局

下一篇: 如何防止ctrl + c在Java中杀死产生的进程