Ganesh S Ganesh S - 5 months ago 85
Java Question

How to stop a command being executed after 4-5 seconds through process builder?

Reference code :

ProcessBuilder ps4;
Process pr4 = null;

String batchFile3 = new File(path + "/src/");

ps4 = new ProcessBuilder(batchFile3.getAbsolutePath());

ps4.redirectErrorStream(true); File(path + "/src/"));

pr4 = ps4.start();

BufferedReade readRun = new BufferedReader(new InputStreamReader(pr4.getInputStream()));



String line,stre;

while ((line = readRun.readLine()) != null) {

System.out.print("-----" + line);

if (line != null) {

stre += line;



  • Here I have result in stre string it might be error or output generated by batch file which I am executing.

  • I want to stop execution of batch file if it is taking more that 4-5 seconds to exectute and kill that batch file execution process.

  • also in that case I should be able to return back to program to process a block which will execute only if this delay in processing of batch file occurs other wise that block should not be processed.


As I understand it you want to stop a subprocess if it runs longer than four or five seconds. This cannot be done directly with ProcessBuilder (you can see that no relevant method exists in the class), but you can implement this behavior easily enough once the subprocess has begun.

Calling 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 the .waitFor() is overloaded, and its sibling takes a timeout argument.

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.

You can use this in tandem with Process.destroy() to stop the process if it takes too long. For example:

Process process = new ProcessBuilder(command, and, arguments)

// Option 1
boolean finished = process.waitFor(5, TimeUnit.SECONDS);
if (!finished) {
  process.waitFor(); // wait for the process to terminate

// Option 2
process.waitFor(5, TimeUnit.SECONDS);
process.waitFor(); // wait for the process to terminate

In practice options 1 and 2 are almost identical, but there are some slight differences.

Option 1:

  • Pro: More directly follows the spec; Process doesn't document what happens when .destroy() is called on an already-terminated subprocess, so we only call it when we believe the subprocess is still running.
  • Con: The process could easily terminate in-between .waitFor() returning and .destroy() being called, leading to a race condition.

Option 2:

  • Pro: Simpler, has no issues with race conditions. The process will be terminated if it's still running.
  • Con: Relies on undocumented behavior of Process.destroy() to no-op when called on an already-finished subprocess.

In practice you should prefer Option 2; Process.destroy() does no-op when called on a terminated subprocess, and even if it didn't the race condition in Option 1 means such an error would be unavoidable. It would of course be nice if this behavior were documented...

What about Process.destroyForcibly()? Generally speaking you should not call this method (another thing the JDK could be clearer about), however if a process is truly hung it may become necessary. Ideally you should ensure your subprocesses are well-behaved, but if you must use .destroyForcibly() this is how I would recommend doing so:

// Option 3
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

This ensures that misbehaving processes will be killed promptly, while still giving properly implemented programs time to exit upon being instructed. The exact behavior of .destroy() and .destroyForcibly() is OS-specific, but on Linux we can see that 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(), and I would suggest only adding it if you discover it is necessary.

It's easy enough to replicate Process.waitFor(long, TimeUnit) in Java 7, there's nothing magic about the default Java 8 implementation:

public boolean waitFor(long timeout, TimeUnit unit)
    throws InterruptedException
    long startTime = System.nanoTime();
    long rem = unit.toNanos(timeout);

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