如何通过流程生成器在4-5秒后停止执行命令



参考代码:

ProcessBuilder ps4;
Process pr4 = null;
String batchFile3 = new File(path + "/src/example.sh");
ps4 = new ProcessBuilder(batchFile3.getAbsolutePath());
ps4.redirectErrorStream(true);
ps4.directory(new File(path + "/src/"));
pr4 = ps4.start();
BufferedReade readRun = new BufferedReader(new InputStreamReader(pr4.getInputStream()));

if(pr4.waitFor()==0)
{
}
 String line,stre;   
while ((line = readRun.readLine()) != null) {
     System.out.print("-----" + line);
     if (line != null) {
           stre += line;
    }
}
  • 这里我在stre字符串中得到的结果可能是错误,也可能是我正在执行的批处理文件生成的输出。

  • 如果执行和终止批处理文件执行过程需要超过4-5秒,我想停止批处理文件的执行。

  • 在这种情况下,我应该能够返回到程序来处理一个块,该块只有在批处理文件的延迟发生时才会执行,而不应该处理该块。

据我所知,如果子流程运行时间超过四五秒,您需要停止它。这不能直接用ProcessBuilder来完成(您可以看到类中不存在相关的方法),但一旦子流程开始,您就可以很容易地实现这种行为。

像在示例代码中那样调用Process.waitFor()是有问题的,因为它会无限期地阻塞当前线程-如果进程花费的时间超过5秒,.waitFor()不会停止它。但是.waitFor()重载,它的同级使用timeout参数。

public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException

如有必要,使当前线程等待,直到此Process对象表示的子进程终止或指定的等待时间过去。

如果过程花费太长,可以将其与Process.destroy()一起使用以停止该过程。例如:

Process process = new ProcessBuilder(command, and, arguments)
    .redirectErrorStream(true)
    .directory(workingDir)
    .start();
process.waitFor(5, TimeUnit.SECONDS);
process.destroy();
process.waitFor(); // wait for the process to terminate

这取决于这样一个事实,即当对已经完成的子流程调用Process.destroy()时,它是一个非操作。在Java9之前,这种行为没有被记录在案,但在实践中一直都是这样。另一种选择是检查.waitFor()的返回值,但这将引入TOCTTOU竞赛。

Process.destroyForcibly()呢?一般来说,您不应该调用这个方法(JDK可能更清楚的另一件事),但是,如果一个进程真的挂起了,它可能会变得必要。理想情况下,您应该确保您的子流程表现良好,但如果您必须使用.destroyForcibly(),我建议您这样做:

// Option 2
process.waitFor(5, TimeUnit.SECONDS);  // let the process run for 5 seconds
process.destroy();                     // tell the process to stop
process.waitFor(10, TimeUnit.SECONDS); // give it a chance to stop
process.destroyForcibly();             // tell the OS to kill the process
process.waitFor();                     // the process is now dead

这确保了行为不端的进程将被迅速杀死,同时仍然给了正确执行的程序在接到指令后退出的时间。.destroy().destroyForcibly()的确切行为是特定于操作系统的,但在Linux上,我们可以看到它们对应于SIGTERMSIGKILL:

int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
kill(pid, sig);

您应该很少需要调用.destroyForcibly(),我建议只有在您发现有必要时才添加它。

选项2在概念上类似于使用timeout命令,如:

$ timeout --kill-after=10 5 your_command

在Java7中复制Process.waitFor(long, TimeUnit)很容易,默认的Java8实现没有什么神奇之处:

public boolean waitFor(long timeout, TimeUnit unit)
    throws InterruptedException
{
    long startTime = System.nanoTime();
    long rem = unit.toNanos(timeout);
    do {
        try {
            exitValue();
            return true;
        } catch(IllegalThreadStateException ex) {
            if (rem > 0)
                Thread.sleep(
                    Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100));
        }
        rem = unit.toNanos(timeout) - (System.nanoTime() - startTime);
    } while (rem > 0);
    return false;
} 

Process提供并在JavaDoc中记录的方法是Process#destroyForcibly()。但是,强制销毁进程并不总是可能的,进程是否真的被终止在很大程度上取决于操作系统和JRE实现。

有关更多详细信息,请参阅JavaDoc。

相关内容

  • 没有找到相关文章

最新更新