【问题标题】:Process.waitFor hangs even though stdout and stderr get read即使 stdout 和 stderr 被读取,Process.waitFor 也会挂起
【发布时间】:2018-03-18 20:41:27
【问题描述】:

我已经在网上搜索过了,process.waitFor() never returns 的问题表明它的 stdout 或 stderr 没有被读取通常是进程的问题。

我们使用ProcessBuilderredirectOutputredirectError 来实现这一点,我认为我们应该安全起见,请参阅以下我们用来执行进程的方法:

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

MetricCalc 的主要方法是这样的

public static void main(String[] args) {
    .... do some stuff ...
    System.err.println("Finished Metrics");
}

表示读取正常,Java程序的最后一行已经执行完毕,进程应该已经终止了。

有人知道为什么进程没有终止/它仍然挂在Process.waitFor() 上吗?

【问题讨论】:

  • " .... 并且进程应该已经终止了。" - 假设子进程正在按照您的预期工作。检查子进程是否已经真正终止;例如使用“ps -efl”或类似的。
  • @StephenC:我用ps -efl | grep "java -Xmx8G"还是可以找到的,说明还没有终止。然而,我不知道为什么会出现这种情况,因为 MetricCalc 的最后一行代码(作为进程运行的 java 程序)已被执行......
  • 哦,我突然想到了:可能 MetricCalc 有一些非守护线程正在运行,这会阻止应用程序终止...我必须对此进行测试...

标签: java process stdout processbuilder stderr


【解决方案1】:

不是Process.waitFor() 的问题,而是进程终止的问题。

启动的 java 应用程序使用了一个ExecutorService,它没有被正确地击落,并且让僵尸线程保持活动状态,从而阻止了进程终止。

添加executorService.shutdown() 解决了问题,应用程序现在按预期终止。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多