【问题标题】:Terminate long-running process _and_ receive stdout in Java终止长时间运行的进程_并_在 Java 中接收标准输出
【发布时间】:2014-12-19 14:52:46
【问题描述】:

我正在尝试使用 Process API 从 Java 运行本机可执行文件。本机代码执行长时间运行的计算,可能必须在超时后中断。

理想情况下,我希望使用getInputStream() 接收标准输出,避免使用中间文件。

这是一个难题:

  1. 不可能首先等待进程终止,然后然后开始读取标准输出。在这种情况下,waitFor 会无限期地等待。
  2. 如果我首先开始读取标准输出并然后检查退出代码,代码将停止响应Thread.interrupt()。要查看问题,请参阅以下“最小”示例:

computation.sh 中模拟长时间运行(5 秒)计算的 Bash 代码:

    #!/bin/bash

    END=$((`date +%s` + 5))
    while [ `date +%s` -lt $END ]; do
        echo "Heavy computation" > /dev/null
    done

    echo "Answer is 42"

Test.java 中的 Java 代码在单独的线程中运行 Bash 代码并在 1 秒后中断它:

    import java.io.*;

    public class Test {

        public static void main(String[] args) throws InterruptedException {

            Thread waitForProcess = new Thread() {

                @Override
                public void run() {
                    Process unixProcess = null;
                    try {
                        unixProcess = new ProcessBuilder("./computation.sh").start();

                        try (BufferedReader stdout = new BufferedReader(
                            new InputStreamReader(unixProcess.getInputStream()))) {

                            String line;
                            // Exactly here, Java stops
                            // responding to Thread.interrupt():
                            while ((line = stdout.readLine()) != null) {
                                System.out.println(line);
                            }
                        }

                        int retval = unixProcess.waitFor();
                        System.out.println("Retval: " + retval);

                    } catch (InterruptedException ex) {
                        System.out.println("Computation interrupted.");

                    } catch (IOException ex) {
                        System.out.println("IOException: " + ex);

                    } finally {
                        if (unixProcess != null) {
                            unixProcess.destroy();
                        }
                    }
                }
            };

            waitForProcess.start();
            // Timeout of 1000 ms
            waitForProcess.join(1000L);
            waitForProcess.interrupt();
            // Additional grace time
            waitForProcess.join(100L);

            // Timeout has occured
            if (waitForProcess.isAlive()) {
                System.out.println("Timeout occurred");
            }
        }
    }

理想情况下,Java 代码应该打印 Timeout occurred 并在 1 秒后退出。事实上,它等待了全部 5 秒,最终打印出Answer is 42

有什么帮助吗?

【问题讨论】:

    标签: java process timeout interrupt


    【解决方案1】:

    您需要两个线程:一个用于读取输入,另一个用于处理超时。

    【讨论】:

    • 我知道你的意思,但这似乎没有帮助。如果我创建 2 个额外线程,#1​​ 用于超时,#2 用于读取标准输出,线程 #2 不会收到相关异常。
    • 你不需要中断第二个线程:一旦进程终止,流将被关闭,它会以这种方式得到通知。
    猜你喜欢
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    • 2011-02-07
    • 2015-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多