import java.lang.ProcessBuilder.Redirect;
public class Main {
public static void main(String args[]){
ProcessBuilder pb = new ProcessBuilder(args);
try{
Process p = pb.start();
System.out.println("child process is alive: " + p.isAlive());
System.out.println("child process pid: " + p.pid());
System.out.println("parent of child process: " + p.toHandle().parent().get().pid());
System.out.println("child process is alive: " + p.isAlive());
p.waitFor();
} catch (Exception e) {
System.out.println("some exception with start process.");
e.printStackTrace();
}
}
}
在Ubuntu 18.04上,我运行程序运行外部程序qazxsw poi没有问题:
sleep 10
但是当我运行该程序来运行外部程序$ java Main sleep 10
child process is alive: true
child process pid: 20559
parent of child process: 20539
child process is alive: true
$
时
echo hello
为什么它在第11行$ java Main echo hello
child process is alive: false
child process pid: 18534
some exception with start process.
java.util.NoSuchElementException: No value present
at java.base/java.util.Optional.get(Optional.java:148)
at Main.main(Main.java:11)
的get()
报告错误?
如果我评论第11行,它将运行没有问题。这是为什么?
如果是因为孩子在第11行打电话给p.toHandle().parent().get().pid()
之前退出,
p.toHandle().parent().get().pid()
发生在NoSuchElementException
而不是之前的get()
或toHandle()
的第11行的parent()
?p.toHandle().parent().get().pid()
时为什么没有这样的问题?我该怎么做才能解决问题呢?例如,我怎样才能让孩子持续更长时间,以便p.pid()
可以工作,即使我在子进程中运行一个短期程序?
p.toHandle().parent().get().pid()
调用时,为什么从parent()
返回的可选项为空?因为子进程非常短,并且当您到达要求父进程的命令时,子进程不再存在。因此,无法再查询操作系统。
echo hello
或getHandle()
时为什么不会发生这种情况?请注意,这些都不是pid()
。这意味着API保证将在其中返回值。实际上,只要操作系统创建进程并在Optional
中返回,实现就会创建句柄 - 包括进程ID。所以你有一个句柄,你有一个进程ID - 但是当你使用它时,不保证具有该ID的进程是活的。
pb.start()
明确告诉您不要对基础过程的活跃性或身份做出假设。
documentation调用目前通过使用子代的pid查询操作系统来实现。因此,在创建流程时,父级不是流程记录的一部分,并且在您调用流程时,它可能不再可用。
无论何时使用parent()
,都不要使用Optional
。特别是不要事先检查它是否存在(并使用get
... isPresent
被认为是“反模式”)。当你看到API给你一个get
时,如果Optional
恰好是空的,请想想你想做什么。不要做出文档不合理的假设。
在这种情况下,您可能希望在未找到父项时显示默认消息。例如:
Optional
或者您可以使用当前进程的pid作为默认值,或者您可以提出的任何其他内容。或者,如果父母的身份对于您的工作是绝对必要的,您可能会抛出不同类型的异常。有关优雅使用它的各种方法,请参阅System.out.println("parent of child process: "
+ p.toHandle().parent().map(ProcessHandle::pid)
.map(Object::toString)
.orElse("not available"));
的文档。
没有办法扩展底层进程 - 你可以使用一个shell脚本在执行你已经通过的命令后休眠,但我发现这个解决方案充其量只是笨重。