java:关闭子进程std流?

时间:2011-04-19 16:57:08

标签: java subprocess blocking

来自java.lang.Process的javadoc的

  

创建进程的方法可能不适用于某些本机平台上的特殊进程,例如本机窗口进程,守护程序进程,Microsoft Windows上的Win16 / DOS进程或shell脚本。创建的子进程没有自己的终端或控制台。其所有标准io(即stdin,stdout,stderr)操作将通过三个流(getOutputStream(),getInputStream(),getErrorStream())重定向到父进程。父进程使用这些流向子进程提供输入并从子进程获取输出。由于某些本机平台仅为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞甚至死锁。

我知道这个问题,当然,如果你想与它进行通信,那么及时与子流程进行沟通是有意义的。

但是如果您只是想启动一个进程并且不关心I / O呢?在Java中是否有一种方法可以释放父进程中专用于管理子进程的资源? (例如I / O管道并等待子进程退出状态)

如果我在父进程中执行以下命令:

  Process.getOutputStream().close();
  Process.getInputStream().close();
  Process.getErrorStream().close();

我还要担心死锁吗? (例如,如果子进程连续向其自己的stdout发送数据)

1 个答案:

答案 0 :(得分:2)

这里有两件事需要担心:

  1. 进程是否阻塞,尝试写入stdout,因为你没有使用它,
  2. 流程如何解释正在关闭的流?
  3. 清除输出流不会导致死锁,除非进程需要输入。但是,进程检测到已到达流的末尾,并可能相应地终止。以grep为例。当您关闭其输入流时,此程序将终止。

    忽略输入的最简单和最安全的方法是创建一个在单独线程上使用和丢弃输入的库。你可能已经看到了StreamGobbler那个漂浮在其周围的课程。

    修改

    所以我尝试了以下两个不同的子进程程序:

    Process proc = new ProcessBuilder(appStr).start();
    proc.getInputStream().close();
    
    InputStream eos = proc.getErrorStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(eos));
    for ( String line = null; (line = reader.readLine()) != null; ) {
       System.err.println(line);
    }
    
    System.out.println(proc.waitFor());
    

    我第一次调用了一个简单的Java应用程序:

    public class App {
       public static void main(String[] args) throws Exception {
          for ( int i = 0; i < 1000; i++ ) {
             System.out.println(i);
          }
       }
    }
    

    流程正常结束,父流程终止,显示0退出代码。

    但后来我尝试针对本机程序调用它,在本例中为cat变体,回显文件。在这种情况下,子进程失败并向错误流写入一个乱码消息,抱怨标准输出流已关闭。它以非零退出代码异常终止。

    因此,在一般情况下,关闭流的建议真的不会成功。您必须知道子进程可以优雅地处理丢失其输出流,我怀疑大多数应用程序都不会。我的直觉是,当输出流关闭时,Java可以做一些优雅的失败,这样从程序的角度来看,流仍然是打开的,没有人听。