Java:Windows中的waitfor()孙子进程

时间:2018-08-02 01:12:29

标签: java windows subprocess

是否有办法不仅等待我产生的进程,还要等待子进程的存在?

示例:我的Java进程A产生了进程B(进程B不是由我编码),而B刚启动了进程C并关闭。我可以让进程A也等待C吗?

谢谢。

1 个答案:

答案 0 :(得分:0)

对于Java 9+,您可以使用java.lang.ProcessHandle界面。该接口有两个方法children()descendants(),它们都返回Stream<ProcessHandle>。区别在于children()仅返回直接后代,而descendants()返回所有后代。 ProcessHandle中也提供了java.lang.Process的某些方法,但是您可以通过调用ProcessHandle获得Process.toHandle()

然后,您将使用onExit()方法,该方法返回一个您可以等待的CompletableFuture(并可以选择在进程退出时添加行为)。

下面是一个示例,其中Main启动Child,然后启动GrandChild

Main.java

import java.util.concurrent.CompletableFuture;

public class Main {

    public static void main(String[] args) throws Exception {
        Process proc = new ProcessBuilder("java", "Child").inheritIO().start();
        proc.onExit().join();
        proc.descendants().map(ProcessHandle::onExit).forEach(CompletableFuture::join);
        System.out.println("Main exiting");
    }
}

Child.java

public class Child {

    public static void main(String[] args) throws Exception {
        new ProcessBuilder("java", "GrandChild").inheritIO().start();
        System.out.println("Child exiting...");
    }

}

GrandChild.java

public class GrandChild {

    public static void main(String[] args) throws Exception {
        System.out.println("GrandChild sleeping...");
        Thread.sleep(5_000L); // 5 seconds
        System.out.println("GrandChild exiting...");
    }

}

GrandChild类休眠5秒钟以模拟工作。 Child类仅启动GrandChid,然后退出以模拟启动更长运行时间的进程的过程。

Main中,我呼叫proc.onExit().join(),然后等待每个后代,以允许Child进程时间实际启动其自己的子进程(GrandChild)。

由于启动单独的进程所涉及的异步性,我不能保证descendants()会涵盖您希望启动的所有进程。例如,如果每个子进程可以任意生成自己的子进程,则情况将变得更加复杂。 descendants()children()都返回快照,这意味着子进程可能会在您调用两个方法之一后 启动。


如果您控制所有后代进程的代码,则让每个子进程在退出自己的子进程之前等待其所有子进程退出可能更容易。每个进程都是Java程序的示例:

Main.java

public class Main {

    public static void main(String[] args) throws Exception {
        new ProcessBuilder("java", "Child").inheritIO().start().waitFor();
        System.out.println("Main exiting");
    }
}

Child.java

public class Child {

    public static void main(String[] args) throws Exception {
        new ProcessBuilder("java", "GrandChild").inheritIO().start().waitFor();
        System.out.println("Child exiting...");
    }

}

GrandChild.java

public class GrandChild {

    public static void main(String[] args) throws Exception {
        System.out.println("GrandChild sleeping...");
        Thread.sleep(5_000L); // 5 seconds
        System.out.println("GrandChild exiting...");
    }

}

每个进程在这里等待其子进程通过Process.waitFor()退出。这具有在Java 8及更低版本上运行的优势(waitFor()从1.0开始就存在)。由于每个进程都在等待其子进程退出,因此第一个祖先只会在所有个后代进程退出后退出。

这里的概念与第一个示例中的相同,除了逻辑由每个进程单独处理而不是由“主”进程中的全部处理。