【问题标题】:How to prevent ctrl+c killing spawned processes in Java如何防止 ctrl+c 在 Java 中杀死生成的进程
【发布时间】:2014-09-20 16:03:04
【问题描述】:

[注意。这与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+c Java程序外部程序也被杀死,这不是我想要的。

我在 Ubuntu 上使用 OpenJDK 1.6。

Edit1:将执行更改为

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

没用。

Edit2:如How to gracefully handle the SIGKILL signal in Java 中所述添加关闭挂钩不会阻止 Ctrl+c 被传播到子级。

【问题讨论】:

  • 这是在哪个操作系统中? Unix/Linux?
  • *.com/questions/2541597/…。这似乎没有灵丹妙药。
  • 可能是$(runit.sh) 可以帮忙吗?

标签: java


【解决方案1】:

Vladimir 给出了我们需要的提示! (对不起,打败了 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 进程中分离出来了!

【讨论】:

    【解决方案2】:

    在 Linux 中,如果您启动另一个进程,它是您的孩子,而您是他的父母。如果父母被杀,所有的孩子都会被杀,他们的孩子也会被杀(多么可怕的暴行)。

    您需要的是启动一个在您退出程序时不会被终止的进程。所以,你需要生的不是你自己的孩子。例如,此处描述了执行此操作的方法:Linux: Prevent a background process from being stopped after closing SSH client 例如使用screen 实用程序。

    【讨论】:

      【解决方案3】:

      你必须让它成为一个守护进程。不要害怕这不是恐怖片。简单地说,您需要将您的进程从控制终端会话中分离出来。我总是以相反的方式来做:启动 Java 的 shell 脚本。

      这里有一个解释:

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

      您也可以使用“jvm 关闭挂钩”,但它们在某些情况下不起作用。

      【讨论】: