7

我使用ProcessBuilder来运行进程。我通过提交在线程池中处理它们的相应runnable来处理输入/输出流(Executors.newCachedThreadPool())。
我得到的结果,但时不时我什么都没有。
例如,如果我这样做:cmd \C dir到进程生成器我得到dir的结果回来,但有时我什么也没有得到(尽管结果似乎从处理process.getInputStream的runnable回来)。
我该如何调试?它显示了intermitently。 使用相同的代码我没有任何问题,当我做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得到结果。
pw是PrintWriter的PW = PrintWriter的(OutputStream中);`其中我通过在可运行

更新2:
似乎:status = process.waitFor();返回较早该处理InputStream的结束该可运行之前。这怎么会发生?我读过javadoc:
the calling thread will be blocked until the subprocess exits。那么这是否意味着我可以在之前返回消耗I/O流?

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

+0

如果进程调用另一个进程,第一个进程可能会过早返回 - 正常行为。 – Sebastian 2013-03-11 10:21:35

+0

这不是关于过早返回。它是关于在输出流消耗之前返回* – Jim 2013-03-11 10:45:46

回答

1

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

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

请注意,冲洗在这里没有帮助,因为它只是确保A有写入的一切。没有办法“强制”B以类似的方式读取数据。

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

编辑一个解决办法是到waitFor()进入流火鸡和转换火鸡成Callable然后你可以提交给执行和使用Future API(example)得到的结果(S)。

+0

那么应该如何修改我的代码来处理呢?我现在只需执行'waitFor'并将流代码读取器中的代码发送出去 – Jim 2013-03-11 10:37:12

+1

'waitFor',然后在包含流处理程序的线程上使用join()。或者让流处理程序在'while()'循环之外调用'waitFor()'使它们在同一个地方。 – 2013-03-11 10:47:32

+0

1)流处理程序被提交给执行程序。我怎样才能“加入”?2)流处理程序如何调用'waitFor'?结果应该被传递给线程,等待进程完成 – Jim 2013-03-11 10:50:42