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

标签 java multithreading outputstream executorservice processbuilder

我使用 ProcessBuilder 来运行进程。我通过在线程池 (Executors.newCachedThreadPool()) 中提交相应的可运行对象来处理输入/输出流。
我得到了结果,但有时我什么也得不到。
例如,如果我这样做: cmd\C dir 到进程构建器,我会得到 dir 的结果,但有时我什么也得不到(尽管结果似乎从处理 process.getInputStream 的 runnable 恢复。
我该如何调试呢?它断断续续地出现。 使用相同的代码,我在执行 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);` 我在 runnable 中传递的

更新 2:
似乎:status = process.waitFor(); 在处理输入流的 runnable 完成之前之前返回。怎么会这样?
我在 javadoc 中读到:
调用线程将被阻塞,直到子进程退出。那么这是否意味着我可以在 使用 I/O 流之前返回?

更新 3:
Ruby 中似乎是同样的问题
IE。 在进程结束和使用输出之间存在一些竞争条件

最佳答案

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

所以 process.waitFor(); 有可能(即使有很多输出)在读取所有缓冲输出之前返回。

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

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

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

关于java - 等待进程和读取流之间的并发问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15334297/

相关文章:

java - C++和Java中的异常处理之间的区别?

multithreading - 线程休眠时的线程与核心

PHP exec - 在进度期间逐行回显输出

java - 如何通过响应 OutputStream 将 zip 文件返回给浏览器?

java - 在 Java 中设置用户注册

java - 将 SAS 日期值转换为 Java YYYY-MM-DD

iphone - 如何在后台线程上定期从服务器轮询数据?

java - urlconnection javax.net.ssl.SSLException : java. lang.IllegalStateException

java - 如何测试用Java写入文件?

c# - 等待所有线程完成,超时