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

我知道如果你在Java中使用ProcessBuilder.start来启动外部进程,你必须使用它的stdout / stderr(例如,见这里 )。 否则外部进程会在启动时挂起。

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

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

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

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

这是自管道诞生以来的标准。 没有多少Java可以做到。

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

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

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

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

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

它在过程的javadoc中解释:

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