调用`ProcessHandle`的`parent()时,“没有值”.get()`

问题描述 投票:0回答:1
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()
  • 在第10行调用p.toHandle().parent().get().pid()时为什么没有这样的问题?

我该怎么做才能解决问题呢?例如,我怎样才能让孩子持续更长时间,以便p.pid()可以工作,即使我在子进程中运行一个短期程序?

java processbuilder processhandle
1个回答
2
投票

当使用p.toHandle().parent().get().pid()调用时,为什么从parent()返回的可选项为空?

因为子进程非常短,并且当您到达要求父进程的命令时,子进程不再存在。因此,无法再查询操作系统。

调用echo hellogetHandle()时为什么不会发生这种情况?

请注意,这些都不是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脚本在执行你已经通过的命令后休眠,但我发现这个解决方案充其量只是笨重。

© www.soinside.com 2019 - 2024. All rights reserved.