Java中的Process Builder和Process - 如何使用超时执行进程:

时间:2011-02-28 06:39:47

标签: java process

我需要在java中执行具有特定超时的外部批处理文件。这意味着如果批处理执行时间超过指定的超时,我需要取消执行。

这是我写的示例代码:

public static void main(String[] args) throws IOException, InterruptedException {
    ProcessBuilder p = new ProcessBuilder("c:\\wait.bat", "25");  // batch file execution will take 25 seconds.
    final long l = System.currentTimeMillis();
    System.out.println("starting..." + (System.currentTimeMillis() - l));
    final Process command = p.start();
    System.out.println("started..." + (System.currentTimeMillis() - l));

    Timer t = new Timer();
    t.schedule(new TimerTask() {

        @Override
        public void run() {
            command.destroy();
        }
    }, 5000);   // it will kill the process after 5 seconds (if it's not finished yet).
    int i = command.waitFor();
    t.cancel();
    System.out.println("done..." + (System.currentTimeMillis() - l));
    System.out.println("result : " + i);

    System.out.println("Really Done..." + (System.currentTimeMillis() - l));
}

批处理文件“wait.bat”是这样的:

@echo off
echo starting the process...
@ping 127.0.0.1 -n 2 -w 1000 > nul
@ping 127.0.0.1 -n %1% -w 1000> nul
echo process finished succesfully
@echo on

正如您在代码中看到的那样,批处理文件需要25秒才能完成(主方法中的第一行),定时器将在5秒后销毁该命令。

这是我的代码输出:

starting...0
started...0
done...5000
result : 1
Really Done...5000
BUILD SUCCESSFUL (total time: 25 seconds)

正如您在输出中看到的那样,最后一行(“Really Done ...”)在第5秒执行,但应用程序在25秒后完成。

我的问题是:即使我在我的计时器中调用了destroy方法,为什么jvm仍然在等待进程完成?

3 个答案:

答案 0 :(得分:8)

它是Windows上Java Process.destroy()实现中的bug。问题是批处理脚本(或其执行的shell)被终止,但不会杀死它自己的子进程(ping这里)。因此,ping仍在.destroy()之后以及.waitFor()之后运行。但不知何故,VM仍在等待ping完成才能完成。

似乎你无法从Java端做到这一点,无法可靠地杀死ping。

您可以考虑使用start(在批处理脚本中或外部)将ping作为单独的进程调用。

(另见previous discussion。)

或者更改为类似unix的操作系统。

答案 1 :(得分:1)

如果您使用Unix / Linux,那么编写一个包装器bash shell脚本以通过超时中断外部命令,然后从Java调用包装器。

包装器脚本看起来像

#!/bin/bash
timeout 60 <your command>

您可以通过检查脚本退出代码(超时情况下为124)来检测超时是否已过期

  

man timeout

答案 2 :(得分:0)

我可能是计时器的取消方法的问题。尝试将计时器作为守护程序线程启动。

Timer t = new Timer(true);