等待进程和读取流之间的并发问题?

时间:2013-03-11 08:44:39

标签: java multithreading outputstream executorservice processbuilder

我使用ProcessBuilder来运行进程。我通过提交在线程池(Executors.newCachedThreadPool())中处理它们的相应runnable来处理输入/输出流。
我得到的结果却时不时地得到任何东西 例如,如果我对流程构建器执行:cmd \C dir,我会得到dir的结果,但有时我得不到任何结果(尽管结果似乎是从处理{{的runnable中恢复的结果1}})。
我该怎么调试呢?它间歇地出现了。 使用相同的代码,当我process.getInputStream时,我没有任何问题。它在我切换到线程池后开始发生。

更新
我想我找到了一些东西:
我在new Thread(runnable).start()

中执行以下操作
Runnable

在不起作用的情况下,它会打印 try { while ( (line = br.readLine()) != null) { pw.println(line); sb.append(line); } System.out.println("Finished reading "+sb.length()); } catch (IOException e) { e.printStackTrace(); } finally{ pw.flush(); try{ isr.close(); }catch(Exception e){} } 。但我尝试通过Finished reading 521而不是pw来获得结果 sb是PrintWriter pw = PrintWriter(outputStream);`我在runnable中传递的

更新2:
似乎:pw返回早于之前处理输入流的runnable完成。怎么会发生这种情况?
我在javadoc中读到:
status = process.waitFor();。那么这是否意味着我可以在消耗I / O流之前返回

更新3:
这似乎是Ruby 中的同一问题 即在流程结束和消费输出之间存在一些竞争条件

1 个答案:

答案 0 :(得分:1)

是。进程之间的stdio是缓冲的(通常是4KB缓冲区)。进程A写入缓冲区并存在。进程B有两个线程;一个等待A的结束而另一个从A读取输出。无法确定哪个线程首先执行。

因此,有可能(甚至可能在有大量输出时)process.waitFor();在读取所有缓冲输出之前返回。

请注意,刷新在这里没有用,因为它只是确保A有所有内容。没有办法“强制”B以类似的方式读取数据。

因此,您应该记住退出状态,并且仅当您从输入流中读取EOF时才将该过程视为“完全终止”。

编辑一种解决方案是将waitFor()移动到流gobbler并将gobbler转换为Callable,然后您可以将其提交给执行者并使用{ {1}} API(example)来获取结果。