微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Java - 使用 TimerTask 杀死外部进程

如何解决Java - 使用 TimerTask 杀死外部进程

我实现了一个方法,其中使用 processBuilder 调用外部程序。如果外部进程花费的时间超过 5 秒(出于测试原因),我想停止该任务。

当我使用 process.exec() 时,实现工作正常。但不适用于 processBuilder.start()

我已经阅读了一些帖子,但它似乎不起作用,因为我无法弄清楚我错过了什么。

方法

ProcessBuilder processBuilder = new ProcessBuilder("/.../test.bat -a -b -c").redirectErrorStream(true);
Process process = processBuilder.start();

Timer t = new Timer();
TimerTask killer = new TimeoutProcessKiller(process);
t.schedule(killer,5 * 1000);

BufferedReader lineReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

lineReader.lines().forEach(str -> LOGGER.log(Level.INFO,str));

int lExitCode = process.waitFor();
if (lExitCode == 0) {
    LOGGER.log(Level.INFO,"Process finished successful.");
} else {
    LOGGER.log(Level.INFO,"Process finished not successful.");
}
killer.cancel();

TimeoutProcessKiller

public class TimeoutProcessKiller extends TimerTask {
    private Process p;

    public TimeoutProcessKiller(Process p) {
        this.p = p;
    }

    public void run() {
        p.destroy();
    }
}

感谢您的建议。

解决方法

您的问题很可能是因为您的批处理脚本启动了在您的任务销毁父进程后仍在运行的子进程。更改 TimeoutProcessKiller.run() 方法以打印出 descendants(子进程及其所有子进程),然后也将它们杀死。

以下将打印每个试图杀死它们的 PID:

public void run() {
    System.out.println("destroying "+p);
    p.destroy();
    System.out.println("destroying descendants");
    p.descendants().peek(System.out::println).forEach(ProcessHandle::destroy);
    System.out.println("destroyed  "+p);
}

您从 Runtime.exec() 更改为 ProcessBuilder 不是原因 - 因为 Runtime.exec() 是对 ProcessBuilder 的调用。如果您不使用 STDOUT 流,后代的问题就会消失(不是忽略的明智之举,因为这会冻结进程),因此您很可能在交换后添加了 BufferedReader lineReader ...来自Runtime.exec()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。