据我了解,如果子进程运行时间超过四到五秒,您希望停止它。这不能直接完成ProcessBuilder https://docs.oracle.com/javase/10/docs/api/java/lang/ProcessBuilder.html(您可以看到类中不存在相关方法),但是一旦子流程开始,您就可以很容易地实现此行为。
Calling Process.waitFor() https://docs.oracle.com/javase/10/docs/api/java/lang/Process.html#waitFor--正如您在示例代码中所做的那样是有问题的,因为它会无限期地阻止您当前的线程 - 如果您的进程花费的时间超过五秒.waitFor()
不会阻止它。然而.waitFor()
已超载且其sibling https://docs.oracle.com/javase/10/docs/api/java/lang/Process.html#waitFor-long-java.util.concurrent.TimeUnit-需要一个timeout
争论。
public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException
如有必要,使当前线程等待,直到此 Process 对象表示的子进程终止,或者指定的等待时间过去。
您可以将其与Process.destroy() https://docs.oracle.com/javase/10/docs/api/java/lang/Process.html#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()
当在已经完成的子流程上调用时是无操作。在 Java 9 之前,这种行为没有记录,但在实践中一直如此。另一种方法是检查返回值.waitFor()
,但这会引入一个托克托竞赛 https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use.
关于什么Process.destroyForcibly() https://docs.oracle.com/javase/10/docs/api/java/lang/Process.html#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()
and .destroyForcibly()
是特定于操作系统的,但在 Linux 上我们可以看到他们对应于SIGTERM and SIGKILL http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/43cb25339b55/src/solaris/native/java/lang/UNIXProcess_md.c#l720:
int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
kill(pid, sig);
您应该很少需要打电话.destroyForcibly() https://stackoverflow.com/q/690415/113632,我建议仅在您发现有必要时才添加它。
选项 2 在概念上类似于使用timeout https://www.gnu.org/software/coreutils/manual/html_node/timeout-invocation.html像这样命令:
$ timeout --kill-after=10 5 your_command
很容易复制Process.waitFor(long, TimeUnit)
在 Java 7 中,没有什么神奇之处默认 Java 8 实现 http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/Process.java#l163:
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;
}