在网上搜索有关如何在Java中运行子进程并处理stdin,stdout和stderr的教程时,我仅找到带有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();
}
我的测试表明,以上解决方案的工作原理很吸引人。但是也许我错过了一些使上述解决方案在特殊情况下无法使用的东西。有任何暗示或疑问吗?