【问题标题】:Java process.waitFor(time, unit) does not time outJava process.waitFor(time, unit) 不会超时
【发布时间】:2019-11-06 02:15:48
【问题描述】:

在我的 Java 11(Debian 下的 openjdk 11.0.3 2019-04-16)程序中,我使用 ProcessBuilder 来启动外部命令。外部命令可能会挂起,因此我需要它在给定时间后超时。

所以我使用应该返回的p.waitFor(time, unit)

如果进程已经退出,则为 true;如果在进程退出之前等待时间已过,则为 false。

        ProcessBuilder pb = new ProcessBuilder(externalCommand);

        // Merges the error stream with the standard output stream
        pb.redirectErrorStream(true);

        Process p = pb.start();

        Date start = new Date();

        BufferedReader br = new BufferedReader(new InputStreamReader(
                p.getInputStream()));

        String tempLine;

        /**
         * We only want the first 10 lines otherwise it will print thousands of
         * useless lines (always the same)
         */
        int nbOfLinesInlogs = 10;

        while ((tempLine = br.readLine()) != null) {

            // We only report errors to the user
            if (tempLine.toLowerCase().startsWith("error") && nbOfLinesInlogs > 0) {
                Level level = Level.WARNING;


                System.err.println("External command output : " + tempLine);
                // There was an error
                errorDetected = true;

                nbOfLinesInlogs--;
            }

        }


        if (p.waitFor(10l,
                TimeUnit.NANOSECONDS)) {

            long elapsedInMillis = new Date().getTime() - start.getTime();
            System.err.println("External process succeeded and took " + elapsedInMillis + " ms");
            // prints Externalprocess succeeded and took 15327 ms
            ...
         }
         else {
            System.err.println("External process timed out");
            // This is never printed!
            throw new InterruptedException(
                    "External process timed out!");
         } 

但是,该过程永远不会超时并打印出它花费了 15 秒,尽管它应该在 10 纳秒后超时(这只是一个测试,以检查超时是否按预期工作)。我还尝试了 µs、ms 和 s,结果相同。

如何让进程在超时时返回 false ?

任何帮助表示赞赏,

【问题讨论】:

  • 我认为... 后面没有隐藏 15 秒的计算价值,在 Date start = new Date();p.waitFor(10l, TimeUnit.NANOSECONDS) 之间?
  • 您正在处理您正在创建的Process 的输入流和错误流吗?根据我对ProcessBuilder 的经验,不正确处理Process 流可能会导致有问题的行为。请记住,您需要在单独的线程中处理流 - 一个用于输入流,另一个用于错误流。
  • @HelloWorld 亚伦的意思是,如果在你开始等待之前有一些事情需要很长时间,那么这个过程实际上可能已经结束了,因为这 15 秒在你开始这个过程和你开始等待的时间。
  • 它不在一个单独的线程中 为什么不呢?正如我之前评论的那样,根据我的经验,它必须位于单独的线程中。做起来并不难,网上有很多例子展示了如何做。
  • 因为你使用了一个while循环,一旦输入关闭,它只会返回false。由于您的输入仅在进程终止时关闭,因此您的检查 (waitFor) 会在进程结束后发生。

标签: java


【解决方案1】:

感谢大家的 cmets。根据上面的cmets,一种解决方法是去掉进程启动和进程等待进程之间的那段代码(waitFor(...)

p = pb.start()
// Everything in-between removed
if(p.waitFor(10l, TimeUnit.MILLISECONDS)) {

// Now this code is not processed in case of time out
}

原因是(见@TreffnonX 评论)

因为我使用了一个 while 循环,一旦输入关闭,它只会返回 false。由于我的输入仅在进程终止时关闭,因此我的检查 (waitFor) 发生在进程结束后。

另一种解决方案可能是启动一个单独的线程来运行这个 while 循环。

【讨论】:

  • 不,不是,也不是“根据上面的 cmets”。没有人这么说。这可能会导致进程无限期地阻止尝试写入其输出,这可能会导致当它完美地工作而忽略其 I/O 时会导致虚假超时。您需要同时消耗所有输出检查超时。
  • @user207421 我不知道您一直在阅读哪些 cmets,但我们确实建议了这一点。此外,建议在单独的线程中读取输出,但可能会发生超时而不会消耗输出。
  • @TreffnonX 我没有看到有人建议不要读取进程输出,但如果你这样做了,那你就错了,并且可能会发生超时因为输出不是被消耗,这只是一个错误导致另一个错误。
  • 如果 OP 只想导致超时,为什么需要读取进程输出?为了让它最终正常工作,他们需要确定地读取输出,但为什么进程需要完成或超时?
猜你喜欢
  • 2019-05-04
  • 1970-01-01
  • 2011-07-25
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-20
相关资源
最近更新 更多