终止长时间运行的进程_and_在Java中接收stdout

时间:2014-12-19 14:52:47

标签: java process timeout interrupt

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

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

这是一个难题:

  1. 首先无法等待进程终止,然后开始读取stdout。在这种情况下,waitFor无限期等待。
  2. 如果我首先开始阅读stdout并然后检查退出代码,则代码停止响应Thread.interrupt()。要查看此问题,请参阅以下“最小”示例:
  3. 模拟长时间运行(5秒)计算的computation.sh中的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

    任何帮助?

1 个答案:

答案 0 :(得分:0)

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