Search code examples
javaprocesstimeoutruntimeexec

How to add a timeout value when using Java's Runtime.exec()?


I have a method I am using to execute a command on the local host. I'd like to add a timeout parameter to the method so that if the command being called doesn't finish in a reasonable amount of time the method will return with an error code. Here's what it looks like so far, without the ability to timeout:

public static int executeCommandLine(final String commandLine,
                                     final boolean printOutput,
                                     final boolean printError)
    throws IOException, InterruptedException
{
    Runtime runtime = Runtime.getRuntime();
    Process process = runtime.exec(commandLine);

    if (printOutput)
    {
        BufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        System.out.println("Output:  " + outputReader.readLine());
    }

    if (printError)
    {
        BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
        System.out.println("Error:  " + errorReader.readLine());
    }

    return process.waitFor();
}

Can anyone suggest a good way for me to implement a timeout parameter?


Solution

  • public static int executeCommandLine(final String commandLine,
                                         final boolean printOutput,
                                         final boolean printError,
                                         final long timeout)
          throws IOException, InterruptedException, TimeoutException {
      Runtime runtime = Runtime.getRuntime();
      Process process = runtime.exec(commandLine);
      /* Set up process I/O. */
      ... 
      Worker worker = new Worker(process);
      worker.start();
      try {
        worker.join(timeout);
        if (worker.exit != null)
          return worker.exit;
        else
          throw new TimeoutException();
      } catch(InterruptedException ex) {
        worker.interrupt();
        Thread.currentThread().interrupt();
        throw ex;
      } finally {
        process.destroyForcibly();
      }
    }
    
    private static class Worker extends Thread {
      private final Process process;
      private Integer exit;
      private Worker(Process process) {
        this.process = process;
      }
      public void run() {
        try { 
          exit = process.waitFor();
        } catch (InterruptedException ignore) {
          return;
        }
      }  
    }