Process.waitFor(),threads和InputStreams

Kal*_*son 32 java multithreading inputstream process

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

Process proc = runtime.exec(command);
processOutputStreamInThread(proc.getInputStream());
processOutputStreamInThread(proc.getErrorStream());
proc.waitFor()
Run Code Online (Sandbox Code Playgroud)

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

根据我所看到的,我猜,command不用有它的所有倒入美联储流输出getInputStream()getErrorStream(),从而使流是空的.

我的试验结果如下:

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

文档仅说明:

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

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

文档仅说明:

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

实现说明:缓冲输入流是个好主意.

一个用户报告说他必须自己关闭流,但是我至少在一部分时间内得到一个异常,表明当我尝试这样做时,流已经关闭.

编辑:getOutputStreamgetInputStream,现在提出上述.

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

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

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

ProcessBuilder pb = new ProcessBuilder(cmdargs);
pb.redirectErrorStream(true);
Process proc = pb.start();
processOutputStream(proc.getInputStream());
proc.waitFor()
Run Code Online (Sandbox Code Playgroud)

Ale*_*yak 29

如果你的外部进程需要它的东西stdin,你必须关闭getOutputStream.否则你会waitFor永远.

下面是Runtime.exec()不会来自JavaWorld的文章,它描述了exec方法的不同缺陷以及如何避免它们.

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

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

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

  • 关于JavaWorld文章,最终解决方案存在一个错误.如果进程非常快地终止,则errorGobbler和outputGobbler可能还没有运行和使用数据.代码应该是:proc.waitFor(); errorGobbler.join(); outputGobbler.join();. 这迫使主线程等待直到流完成读取输入. (4认同)