我想在Java代码中调用外部程序,那么谷歌告诉我,运行或的ProcessBuilder可以帮我做这项工作。 我已经尝试过了,并且有出来一个问题java程序不能退出,这意味着无论是子进程和父进程等待永远。 他们都挂或死锁。
有人告诉我的原因是子进程的高速缓存太小。 当它试图将数据回馈给父进程,但父进程在时间上不读它,然后他们都挂起。 因此,他们建议我叉的线程来负责读取子进程的缓存数据。 我这样做是因为他们告诉我,但仍有一些问题。
然后我关闭它通过该方法获得的getOutputStream输出流()。 最后,该项目的成功。 但我不知道为什么会发生? 是否有输出蒸汽和输入流之间的一些关系?
你已经在你的问题提供了非常少量细节,所以我只能提供一般的答案。
所有的过程有三个标准流:标准输入,标准输出和标准错误。 标准输入用于在数据,标准输出用于写出数据,以及标准误差为读出写入错误消息。 当你开始使用外部程序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
并确保您调用它的redirectErrorStream()
方法具有true
的价值。 调用此方法的外部程序的标准错误重定向到其标准输出,所以你只能有一个流的读取。