java - 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();
}
我的测试表明,上述解决方案就像一个魅力。但也许我错过了一些使上述解决方案在特殊情况下无法使用的东西。有任何提示或疑问吗?