首页 > 解决方案 > ProcessBuilder 和 gobbler 线程

问题描述

在网上搜索如何在 Java 中运行子进程并处理标准输入、标准输出和标准错误的教程时,我只找到了使用 gobbler 线程的解决方案。使用 gobbler 线程意味着为每个子进程调用创建、调度和清理 3 个线程。如果只调用几个进程,这个额外的开销无关紧要,但是如果调用了数千个子进程,例如编译大量文件,这个开销会产生可测量的更长的处理时间。此外,使用 gobbler 线程使实现更加复杂。

所以我的问题是为什么使用这种低效和复杂的解决方案很常见?

下面是一个更简单、更有效的解决方案:

private void runProcess() throws IOException, InterruptedException {
  this.prc = new ProcessBuilder(this.commandLine.split(" ")).start();

  Iterator<String> it = this.getInputstreamList().iterator();
  StringBuilder stdOut = new StringBuilder();
  StringBuilder stdErr = new StringBuilder();

  try (BufferedWriter stdInBw = new BufferedWriter(new OutputStreamWriter(this.prc.getOutputStream()), 65536)) {
    while (it.hasNext()) {
      String line = it.next();
      stdInBw.write(line + "\n");
    }
    stdInBw.flush();
  }
  try (BufferedReader stdOutBr = new BufferedReader(new InputStreamReader(this.prc.getInputStream()), 65536)) {
    try (BufferedReader stdErrBr = new BufferedReader(new InputStreamReader(this.prc.getErrorStream()), 65536)) {
      while (true) {
        while (stdOutBr.ready()) {
          String line = stdOutBr.readLine();

          if (line == null) {
            break;
          }
          stdOut.append(line + "\n");
        }
        while (stdErrBr.ready()) {
          String line = stdErrBr.readLine();

          if (line == null) {
            break;
          }
          stdErr.append(line + "\n");
        }
        if (!this.prc.isAlive()) {
          break;
        }
        this.prc.waitFor(50, TimeUnit.MILLISECONDS);
      }
    }
  }
  this.retVal = prc.exitValue();
  this.stdOut = stdOut.toString();
  this.stdErr = stdErr.toString();
}

我的测试表明,上述解决方案就像一个魅力。但也许我错过了一些使上述解决方案在特殊情况下无法使用的东西。有任何提示或疑问吗?

标签: javaprocessbuilder

解决方案


推荐阅读