Process.waitFor(),threads和InputStreams

时间:2010-01-27 22:19:48

标签: java multithreading process inputstream

在伪代码中,这就是我正在做的事情:

Process proc = runtime.exec(command);
processOutputStreamInThread(proc.getInputStream());
processOutputStreamInThread(proc.getErrorStream());
proc.waitFor()

但是,有时processOutputStreamInThread看不到任何输出,有时也看不到。粗略地说,该方法创建命令输出的BufferedInputStream并将其发送给记录器。

基于我所看到的,我猜测command不需要将它的所有输出转储到由getInputStream()getErrorStream()提供的流中,从而允许流到是空的。

我的试验结果如下:

(1) java.lang.Process中的waitFor()是否要求已执行程序的输出在返回之前已被读取?

文档仅说明:

  

导致当前线程在必要时等待,直到此Process对象表示的进程终止。如果子进程已终止,则此方法立即返回。如果子进程尚未终止,则调用线程将被阻塞,直到子进程退出。

(2)在什么条件下,getInputStreamgetErrorStream提供的流需要关闭和/或是否会自动关闭?

文档仅说明:

  

获取子进程的错误流。该流获取从此Process对象表示的进程的错误输出流中传输的数据。

     

实施说明:对输入流进行缓冲是一个好主意。

他必须自己关闭一个user reports,但是我至少在一部分时间内得到一个例外,表示当我尝试这样做时,该流已经关闭。

修改:将getOutputStream更改为getInputStream,现在显示在上方。

解决方案:问题最终导致在某些情况下用于处理输出流的线程在我的非常短暂的进程完成之后才会运行,导致输入流给出我没有数据。 waitFor没有等待执行程序的输出。相反,程序在收集任何输出之前运行并终止。

我使用了线程,因为我不确定我将在标准错误和标准输出上获得多少输出,我希望能够同时处理两个,而不会阻塞其中一个或者只有其中一个有数据可用。但是,因为我的线程无法一致地读取执行程序的输出,所以这是一个非解决方案。

我的最终编码看起来像这样:

ProcessBuilder pb = new ProcessBuilder(cmdargs);
pb.redirectErrorStream(true);
Process proc = pb.start();
processOutputStream(proc.getInputStream());
proc.waitFor()

2 个答案:

答案 0 :(得分:29)

如果您的外部流程需要stdin上的内容,则必须关闭getOutputStream。否则你将永远waitFor

以下是来自JavaWorld的When Runtime.exec() won't article,它描述了exec方法的不同缺陷以及如何避免它们。

根据我的经验,最好使用子进程的STDOUT和STDERR(直到它们为EOF),然后在waitFor中阻塞。希望在这一点上你不必等待很长时间。

回答Kaleb的问题。 在正常情况下,您不应该关闭流,但是因为您是waitingFor并且由于任何原因它没有超时,如果您在输出中遇到某些错误条件,则可能需要关闭这些流。我想进一步处理孩子的输出。但是,子程序在另一端关闭STDOUT或STDERR管道时是否会终止(崩溃)完全取决于该子程序的实现。但是,大多数shell程序将在这种情况下终止。

我真的希望waitFor有一些有意义的超时,Process有一个记录的清理资源的方法,当你决定放弃监控时。

答案 1 :(得分:2)

我认为这有点违反直觉,但是:

  

getOutputStream获取输出   子流程的流程。输出到   流被管道输入标准   输入流程的流程   由此Process对象表示。   实施说明:这是一个好主意   用于缓冲输出流。   返回:连接的输出流   到子进程的正常输入。

我把它作为来自主进程的输出流读取并附加到子进程的标准输入,所以当你写入getOutputStream()。write()时,你实际上是在stdin上写的。

你可能想使用.getInputStream()?

  

返回:       输入流连接到子流程的正常输出。

对于Process.Waitfor(),API文档说:

  

导致当前线程等待,如果   必要的,直到过程   由此Process对象表示   终止。此方法返回   如果子进程有,立即   已经终止了。如果是子进程   还没有终止,呼唤   线程将被阻止,直到   子进程退出。

我会说这个被调用的线程将被阻塞,直到进程执行完毕为止 - 你可能仍然在这个阶段处理输出,这取决于其他线程,或者它们可能在你的线程返回之前完成。