我试图将ProcessBuilder用于像“' ls”这样简单的事情。命令。我已经阅读了在waitFor()调用返回之前需要完成的流程流的问题,但即使将错误重定向到输出并消除了流,流程也永远不会返回。
public class ProcessTest {
public static void main(String[] args) throws Exception {
ProcessBuilder builder = new ProcessBuilder();
builder.command("ls");
builder.redirectErrorStream(true);
Process process = builder.start();
StreamGobbler streamGobbler = new StreamGobbler(process.getInputStream(), System.out::println);
Executors.newSingleThreadExecutor().submit(streamGobbler);
int exitCode = process.waitFor();
}
}
与StreamGlobber一起成为一个天真的消费者:
public class StreamGobbler implements Runnable {
private InputStream inputStream;
private Consumer<String> consumer;
public StreamGobbler(InputStream inputStream, Consumer<String> consumer) {
this.inputStream = inputStream;
this.consumer = consumer;
}
@Override
public void run() {
new BufferedReader(new InputStreamReader(inputStream)).lines().forEach(consumer);
}
}
有人能告诉我这里出了什么问题吗?
答案 0 :(得分:0)
问题不在于处理外部流程,而是由ExecutorService
返回的Executors.newSingleThreadExecutor()
的错误使用。此方法创建在后台运行的线程,并且因为您永远不会关闭此执行程序(这将停止该线程),此线程会阻止JVM退出。
如果您愿意,可以通过添加打印出退出代码的行来证明ls
进程退出。但请注意,此行可能不会出现在输出的底部。
要解决此问题,我们需要保留对已创建的ExecutorService
的引用,然后在我们不再需要时将其关闭。尝试替换
Executors.newSingleThreadExecutor().submit(streamGobbler);
int exitCode = process.waitFor();
与
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(streamGobbler);
int exitCode = process.waitFor();
executor.shutdown();
我对你的代码做了这个改动,它从挂起到彻底退出。