如何通过进程构建器在 4-5 秒后停止执行命令?
How to stop a command being executed after 4-5 seconds through process builder?
参考代码:
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;
}
}
这里我得到了 str 字符串,它可能是我正在执行的批处理文件产生的错误或输出。
如果执行批处理文件的时间超过 4-5 秒,我想停止执行批处理文件并终止该批处理文件执行进程。
同样在那种情况下,我应该能够 return 回到程序来处理一个块,该块只有在处理批处理文件的延迟发生时才会执行,否则该块不应该执行待处理。
Process
提供并记录在 JavaDoc 中的方法是 Process#destroyForcibly()
。但是,并非总是可以强制销毁进程,进程是否真正终止在很大程度上取决于操作系统和 JRE 实现。
详情请参阅JavaDoc。
据我了解,如果子进程运行时间超过四或五秒,您希望停止该子进程。这不能直接用 ProcessBuilder
完成(你可以看到 class 中不存在相关方法),但是一旦子进程开始,你就可以很容易地实现这个行为。
调用 Process.waitFor()
as you do in your sample code is problematic because it will block your current thread indefinitely - if your process takes longer than five seconds .waitFor()
will not stop it. However .waitFor()
is overloaded and its sibling 需要一个 timeout
参数。
public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException
Causes the current thread to wait, if necessary, until the subprocess represented by this Process object has terminated, or the specified waiting time elapses.
您可以将它与 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()
在已完成的子进程上调用时是空操作这一事实。在 Java 9 之前,没有记录这种行为,但在实践中一直如此。另一种方法是检查 .waitFor()
的 return 值,但这会引入 TOCTTOU race.
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()
的确切行为是 OS 特定的,但在 Linux 上我们可以看到 they correspond to SIGTERM
and SIGKILL
:
int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
kill(pid, sig);
You should rarely have a need to call .destroyForcibly()
,我建议仅在您发现有必要时添加它。
选项 2 在概念上类似于使用 timeout
命令,如下所示:
$ timeout --kill-after=10 5 your_command
在Java中复制Process.waitFor(long, TimeUnit)
很容易 7,default Java 8 implementation没有什么神奇的:
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;
}
参考代码:
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;
}
}
这里我得到了 str 字符串,它可能是我正在执行的批处理文件产生的错误或输出。
如果执行批处理文件的时间超过 4-5 秒,我想停止执行批处理文件并终止该批处理文件执行进程。
同样在那种情况下,我应该能够 return 回到程序来处理一个块,该块只有在处理批处理文件的延迟发生时才会执行,否则该块不应该执行待处理。
Process
提供并记录在 JavaDoc 中的方法是 Process#destroyForcibly()
。但是,并非总是可以强制销毁进程,进程是否真正终止在很大程度上取决于操作系统和 JRE 实现。
详情请参阅JavaDoc。
据我了解,如果子进程运行时间超过四或五秒,您希望停止该子进程。这不能直接用 ProcessBuilder
完成(你可以看到 class 中不存在相关方法),但是一旦子进程开始,你就可以很容易地实现这个行为。
调用 Process.waitFor()
as you do in your sample code is problematic because it will block your current thread indefinitely - if your process takes longer than five seconds .waitFor()
will not stop it. However .waitFor()
is overloaded and its sibling 需要一个 timeout
参数。
public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException
Causes the current thread to wait, if necessary, until the subprocess represented by this Process object has terminated, or the specified waiting time elapses.
您可以将它与 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()
在已完成的子进程上调用时是空操作这一事实。在 Java 9 之前,没有记录这种行为,但在实践中一直如此。另一种方法是检查 .waitFor()
的 return 值,但这会引入 TOCTTOU race.
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()
的确切行为是 OS 特定的,但在 Linux 上我们可以看到 they correspond to SIGTERM
and SIGKILL
:
int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
kill(pid, sig);
You should rarely have a need to call .destroyForcibly()
,我建议仅在您发现有必要时添加它。
选项 2 在概念上类似于使用 timeout
命令,如下所示:
$ timeout --kill-after=10 5 your_command
在Java中复制Process.waitFor(long, TimeUnit)
很容易 7,default Java 8 implementation没有什么神奇的:
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;
}