7

我使用 aProcessBuilder来运行进程。Executors.newCachedThreadPool()我通过在线程池 ( )中提交相应的可运行对象来处理输入/输出流。
我得到了结果,但时不时地我什么也得不到。
例如,如果我这样做:cmd \C dir对于流程构建器,我得到了dir返回的结果,但有时我什么也没得到(尽管结果似乎从处理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. 但我尝试通过pwand not得到结果sb
pw是 PrintWriter pw = PrintWriter(outputStream);` 我在 runnable 中传递的

更新 2:
似乎:在处理输入流的可运行对象完成之前status = process.waitFor();返回。这怎么可能发生? 我在 javadoc 中阅读:. 那么这是否意味着我可以在使用 I/O 流 之前返回?

the calling thread will be blocked until the subprocess exits

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

4

1 回答 1

1

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

process.waitFor();因此,在读取所有缓冲输出之前返回是可能的(即使有很多输出时也是如此) 。

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

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

EDIT One solution would be to move the waitFor() into the stream gobbler and convert the gobbler into a Callable which you could then submit to the executor and use the Future API (example) to get the result(s).

于 2013-03-11T10:21:32.753 回答