【问题标题】:Java ProcessBuilder: Input/Output StreamJava ProcessBuilder:输入/输出流
【发布时间】:2012-07-19 09:10:39
【问题描述】:

我想在 java 代码中调用一个外部程序,然后 Google 告诉我 Runtime 或 ProcessBuilder 可以帮助我完成这项工作。我试过了,出现了java程序无法退出的问题,就是子进程和父进程都在等待。他们正在挂起或陷入僵局。

有人告诉我原因是子进程的缓存太小了。当它试图将数据返回给父进程,但父进程没有及时读取数据时,它们都会挂起。所以他们建议我分叉一个线程来负责读取子进程的缓存数据。我按照他们告诉我的去做,但仍然存在一些问题。

然后我关闭通过getOutputStream()方法得到的输出流。最后,程序成功。但我不知道为什么会这样?输出流和输入流之间有什么关系吗?

【问题讨论】:

  • 您要运行什么外部程序?你可以在命令提示符/终端/shell 中运行这个程序吗?

标签: java outputstream processbuilder


【解决方案1】:

您在问题中提供的细节很少,所以我只能提供一般性的答案。

所有进程都有三个标准流:标准输入、标准输出和标准错误。标准输入用于读入数据,标准输出用于写出数据,标准错误用于写出错误消息。当您使用Runtime.getRuntime().exec()ProcessBuilder 启动外部程序时,Java 将为外部程序创建一个Process 对象,并且此Process 对象将具有访问这些流的方法。

这些流的访问方式如下:

  • process.getOutputStream():返回外部程序的标准输入。这是OutputStream,因为它是您的 Java 代码将写入的内容。
  • process.getInputStream():返回外部程序的标准输出。这是一个 InputStream,因为它是您的 Java 代码将从中读取的内容。
  • process.getErrorStream():返回外部程序的标准错误。这是一个InputStream,就像标准输出一样,它是您的 Java 代码将从中读取的内容。

请注意,getInputStream()getOutputStream() 的名称可能会造成混淆。

您的 Java 代码和外部程序之间的所有流都被缓冲。这意味着每个流都有少量内存(缓冲区),写入者可以在其中写入尚未被读取者读取的数据。写入器不必等待读取器立即读取其数据;它可以将其输出留在缓冲区中并继续。

写入缓冲区和读取缓冲区有两种挂起方式:

  • 在没有足够空间存储数据时尝试将数据写入缓冲区,
  • 正在尝试从空缓冲区中读取。

在第一种情况下,写入器将通过读取数据来等待缓冲区中的空间。第二种,读取器会一直等到数据写入缓冲区。

您提到关闭getOutputStream() 返回的流导致您的程序成功完成。这会关闭外部程序的标准输入,告诉它没有更多内容可供读取。如果您的程序随后成功完成,这表明您的程序在挂起时正在等待更多输入。

如果你确实运行一个外部程序,如果你不需要使用它,你应该关闭它的标准输入,就像你所做的那样,这可能是有争议的。这告诉外部程序将不再有输入,因此消除了它在等待输入时卡住的可能性。但是,它并没有回答为什么您的外部程序正在等待输入的问题。

大多数时候,当您使用Runtime.getRuntime().exec()ProcessBuilder 运行外部程序时,您并不经常使用标准输入。通常,您会在命令行上将所需的任何输入传递给外部程序,然后读取其输出(如果它产生任何输出)。

您的外部程序是否按照您的需要执行然后卡住,显然是在等待输入?您是否需要将数据发送到其标准输入?如果您在 Windows 上使用cmd.exe /k ... 启动一个进程,命令解释器将在它启动的程序退出后继续运行。在这种情况下,您应该使用/c 而不是/k

最后,我想强调一下,有两个输出流,标准输出和标准错误。如果您在错误的时间从错误的流中读取,可能会出现问题。如果您在缓冲区为空时尝试从外部程序的标准输出中读取,您的 Java 代码将等待外部程序生成输出。但是,如果您的外部程序正在向其标准错误写入大量数据,它可能会填满缓冲区,然后发现自己正在等待您的 Java 代码通过读取缓冲区来腾出空间。这样做的最终结果是您的 Java 代码和外部程序都在等待对方做某事,即死锁。

只需使用ProcessBuilder 并确保您使用true 值调用其redirectErrorStream() 方法即可解决此问题。调用此方法会将外部程序的标准错误重定向到其标准输出,因此您只有一个流可供读取。

【讨论】:

  • 很好的解释!非常感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-17
  • 2017-06-09
  • 1970-01-01
  • 2013-04-24
  • 2015-06-18
相关资源
最近更新 更多