我已经在网上搜索过了,问题 process.waitFor() 从不返回表明进程通常是一个问题,他们的 stdout 或 stderr 没有被读取。
我们使用ProcessBuilder
与redirectOutput
和redirectError
来实现这一点,我认为我们应该安全起见,请参阅我们用于执行流程的以下方法:
public static void execute(String directory, long timeout, File out, File err, String... command) throws InterruptedException, IOException {
LOGGER.log(Level.INFO, String.format("executing command %s (%s)", Arrays.toString(command), timeout > 0 ? String.format("timeout = %,d[ms]", timeout) : "no timeout"));
ProcessBuilder builder = new ProcessBuilder();
builder.directory(new File(directory));
builder.command(command);
builder.redirectOutput(out);
if(out == err) {
builder.redirectErrorStream(true);
} else {
builder.redirectError(err);
}
long time = System.currentTimeMillis();
Process process = builder.start();
try {
LOGGER.log(Level.FINE, "waiting for process");
boolean exited = process.waitFor(timeout, TimeUnit.MILLISECONDS);
if(!exited) {
LOGGER.log(Level.WARNING, "timeout reached, trying to destroy ...");
exited = destroy(silent, process); // Helper method to destroy processes
}
long duration = System.currentTimeMillis() - time;
int exitValue = process.exitValue();
LOGGER.log(Level.INFO, "execution finished in " + duration + "[ms] => " + exitValue);
} catch (InterruptedException | Error | RuntimeException e) {
LOGGER.log(Level.SEVERE, "execution failed", e);
throw e;
}
}
然而,问题是它挂在process.waitFor(timeout, TimeUnit.MILLISECONDS)
调用上,即使该过程应该很容易在超时内完成。
日志记录输出为
Oct 07, 2017 12:39:55 AM at.ProcessExecutor execute
INFO: executing command [java, -Xmx8G, -XX:+UseG1GC, -XX:+CrashOnOutOfMemoryError, -jar, MetricCalc.jar] (timeout = 14,400,000[ms])
Oct 07, 2017 12:39:55 AM at.ProcessExecutor execute
FINE: waiting for process
(认识到尚未写入execution finished
行)
err
文件读取
... Things we write to std.err ...
Finished Metrics
而公制计算的主要方法看起来像
public static void main(String[] args) {
.... do some stuff ...
System.err.println("Finished Metrics");
}
这表明读取工作正常,Java 程序的最后一行已执行,进程应已终止。
有人知道为什么该过程不终止/它仍然挂在Process.waitFor()
上吗?
这不是Process.waitFor()
的问题,而是进程终止的问题。
启动的 Java 应用程序使用了一个未正确击落的ExecutorService
,并使僵尸线程处于活动状态,从而阻止了进程终止。
添加executorService.shutdown()
解决了问题,应用程序现在按预期终止。