Java 如果使用了waitFor,为什么杀死JVM也会终止其子进程?

Java 如果使用了waitFor,为什么杀死JVM也会终止其子进程?,java,linux,jvm,Java,Linux,Jvm,如果未使用waitFor,则终止JVM对其子进程没有影响。这里有一个例子 Bash脚本: #!/usr/bin/env bash echo "Sleeping..." > 'log' sleep 30 echo "Wake up" >> 'log' Java代码: public class Code { public static void main(String[] args) throws Exception { Process process = Runti

如果未使用
waitFor
,则终止JVM对其子进程没有影响。这里有一个例子

Bash脚本:

#!/usr/bin/env bash
echo "Sleeping..." > 'log'
sleep 30
echo "Wake up" >> 'log'
Java代码:

public class Code {
  public static void main(String[] args) throws Exception {
    Process process = Runtime.getRuntime().exec("./child.sh");
    // process.waitFor();
  }
}
发出
Java代码
后,JVM立即终止。和
ps-ef | grep'child.sh'| grep-v grep
显示:

jing      3535  2761  0 13:47 pts/15   00:00:00 bash ./child.sh
30秒后,我检查当前目录中
log
文件的内容。内容是:

Sleeping...
Wake up
上面的
grep
命令现在什么也不显示。现在,我取消注释
process.waitFor()
并重新编译
code.java
。在运行
java代码
之后,我使用上面的
grep
命令来验证
child.sh
子进程是否正在运行。然后我发出
Ctrl-C
,JVM终止。现在运行上面的
grep
命令不会显示任何内容。而
日志
文件的内容保持为:

Sleeping...
我已经检查了
进程
的Javadoc,它没有解释这种行为。然后,我使用以下代码检查
fork
execlp
waitpid
系统调用的行为。它表现出同样的行为

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

static void err_sys(const char* msg) {
  printf("%s\n", msg);
  exit(1);
}

int main(void) {
    pid_t   pid;

    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid == 0) {
        if (execlp("/home/jing/code/lintcode/child.sh", "child.sh", (char *)0) < 0)
            err_sys("execlp error");
    }

  if (waitpid(pid, NULL, 0) < 0)
    err_sys("wait error");

  exit(0);
}
有人能解释一下
waitFor
waitpid
的这种效果吗


在MAC平台上询问类似的问题。但它缺乏细节。因此,我在这里针对我的环境问了这个问题。

waitPid()没有什么特别之处,只是将父进程保持在前台


如果您使用fork,然后等待子进程完成,则会有一个(简化的)进程树,如下所示:

─┬= 1 init
 └─┬= 2 bash --login
   └─┬= 3 java code
     └─── 4 bash child.sh
java
是终端中的前台进程,子进程在其进程组中

当您点击^C时,整个前台进程组将被终止


如果您不等待,那么首先您的流程树与上面的流程树相同。
java
进程终止,子进程成为进程树根的子进程

─┬= 1 init
 ├──= 2 bash --login
 └─── 4 bash child.sh
子进程完成执行并正常终止



1流程组收到一个SIGINT,默认操作是终止该SIGINT。但是,可能会安装不同的信号处理程序。

您确定吗?控制终端对于涉及的所有三个过程都是相同的,并且它从不关闭。True。但是它们是如何终止的呢?内核将SIGINT发送到终端中会话的前台进程组。
─┬= 1 init
 ├──= 2 bash --login
 └─── 4 bash child.sh