如果父进程没有在Java中使用stdout / stderr,为什么进程会挂起?

时间:2013-06-07 11:46:59

标签: java process processbuilder

我知道如果您在Java中使用ProcessBuilder.start来启动外部进程,则必须使用其stdout / stderr(例如,请参阅here)。否则外部进程会在启动时挂起。

我的问题是为什么以这种方式运作。我的猜测是JVM将执行过程的stdout / stderr重定向到管道,如果管道没有空间,则对管道的写入阻塞。它有意义吗?

现在我想知道为什么 Java会这样做。这个设计背后的理由是什么?

2 个答案:

答案 0 :(得分:10)

Java在这方面没有做任何事情。它只是使用OS服务来创建管道。

所有类似操作系统和Windows的Unix在这方面表现相同:在父级和子级之间创建一个带有4K的管道。当该管道已满(因为一方未读取)时,写入过程会阻塞。

这是自管道诞生以来的标准。 Java可以做的事情不多。

你可以争辩说Java中的进程API是笨拙的并且没有很好的默认值,比如简单地将子流连接到与父进程相同的stdin / stdout,除非开发人员用特定的东西覆盖它们。

我认为目前的API有两个原因。首先,Java开发人员(即Sun / Oracle的工作人员)确切地知道流程API的工作原理以及您需要做什么。他们非常清楚,他们没有想到API会让人感到困惑。

第二个原因是没有良好的违约对大多数人有效。你无法真正连接父母和孩子的标准差;如果你在控制台上输入一些内容,输入应该进入哪个进程?

同样,如果连接stdout,输出将转到某处。如果您有一个Web应用程序,可能没有控制台,或者输出可能会出现在没有人期望的地方。

管道已满时甚至无法抛出异常,因为在正常操作期间也可能发生异常。

答案 1 :(得分:6)

javadoc of Process

中对此进行了解释
  

默认情况下,创建的子进程没有自己的终端或控制台。它的所有标准I / O(即stdin,stdout,stderr)操作将被重定向到父进程,在那里可以通过使用方法getOutputStream(),getInputStream()和getErrorStream()获得的流来访问它们。父进程使用这些流向子进程提供输入并从子进程获取输出。 由于某些本机平台仅为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子流程的输出流可能导致子进程阻塞甚至死锁。 < / p>