我使用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 中的同一问题
即在流程结束和消费输出之间存在一些竞争条件
答案 0 :(得分:1)
是。进程之间的stdio是缓冲的(通常是4KB缓冲区)。进程A写入缓冲区并存在。进程B有两个线程;一个等待A的结束而另一个从A读取输出。无法确定哪个线程首先执行。
因此,有可能(甚至可能在有大量输出时)process.waitFor();
在读取所有缓冲输出之前返回。
请注意,刷新在这里没有用,因为它只是确保A有写所有内容。没有办法“强制”B以类似的方式读取数据。
因此,您应该记住退出状态,并且仅当您从输入流中读取EOF时才将该过程视为“完全终止”。
编辑一种解决方案是将waitFor()
移动到流gobbler并将gobbler转换为Callable
,然后您可以将其提交给执行者并使用{ {1}} API(example)来获取结果。