Java 中的进程构建器和进程 - 如何在超时的情况下执行进程:?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5138946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 09:38:37  来源:igfitidea点击:

Process Builder and Process in Java - how to execute a process with a timeout :?

javaprocess

提问by mhshams

I need to execute an external batch file in java with a specific timeout. which means that if the batch execution take longer than specified timeout, i need to cancel the execution.

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

here is a sample code that i wrote:

这是我编写的示例代码:

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));
}

the batch file "wait.bat" is something like this:

批处理文件“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

As you see in the code, batch file will take 25 seconds to finish (first line in main method) and the Timer will destroy the command after 5 seconds.

正如您在代码中看到的,批处理文件需要 25 秒才能完成(main 方法中的第一行),并且 Timer 将在 5 秒后销毁命令。

here is the output of my code:

这是我的代码的输出:

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

as you see in output, the last line ("Really Done...") is executed in 5th second but the application is finished after 25 seconds.

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

my question is that : even though i called the destroy method in my timer, why jvm still waiting for the process to be finished ?

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

回答by Pa?lo Ebermann

It is a bugin Java's Process.destroy()implementation on Windows. The problem is that the batch-script (or its executing shell) is killed, but does not kill its own child processes (the ping here). Thus, ping is still running after the .destroy(), and also after the .waitFor(). But somehow the VM still waits for the ping to finish before finishing itself.

这是Java在 Windows 上的实现中的一个错误Process.destroy()。问题是批处理脚本(或其正在执行的 shell)被杀死,但不会杀死它自己的子进程(这里的 ping)。因此,ping 仍然在 之后运行.destroy(),也在.waitFor(). 但不知何故,VM 在完成之前仍然等待 ping 完成。

It seems there is nothing you can do here from the Java side to really kill the ping reliably.

从 Java 方面来看,您似乎无法在这里真正可靠地终止 ping。

You may think about using start(in your batch script or outside) to invoke your ping as a separate process.

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

(See also this previous discussion.)

(另见前面的讨论。)

Or change to a unix-like operation system.

或者换一个类unix的操作系统。

回答by Sergey Grigoriev

If you use Unix/Linux, then write a wrapper bash shell script to interrupt an external command by timeout, then call the wrapper from Java.

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

The wrapper script looks like

包装脚本看起来像

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

You can detect if timeout expired by checking the script exit code which is 124 in case of timeout

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

See

man timeout

人超时

回答by sdorra

I could be a problem with the cancel method of the timer. try to start the timer as daemon thread.

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

Timer t = new Timer(true);