code: public void run() throws IOException {
      if (this.isStarted() || this.isComplete()) {
        throw new IllegalStateException("The process can only be used once.");
      }
  
      final ProcessBuilder builder = new ProcessBuilder(this.cmd);
      builder.directory(new File(this.workingDir));
      builder.environment().putAll(this.env);
      builder.redirectErrorStream(true);
      this.process = builder.start();
      try {
        this.processId = processId(this.process);
        if (this.processId == 0) {
          this.logger.debug("Spawned thread with unknown process id");
        } else {
          this.logger.debug("Spawned thread with process id " + this.processId);
        }
  
        this.startupLatch.countDown();
  
        final LogGobbler outputGobbler =
            new LogGobbler(
                new InputStreamReader(this.process.getInputStream(), StandardCharsets.UTF_8),
                this.logger, Level.INFO, 30);
        final LogGobbler errorGobbler =
            new LogGobbler(
                new InputStreamReader(this.process.getErrorStream(), StandardCharsets.UTF_8),
                this.logger, Level.ERROR, 30);
  
        outputGobbler.start();
        errorGobbler.start();
        int exitCode = -1;
        try {
          exitCode = this.process.waitFor();
        } catch (final InterruptedException e) {
          this.logger.info("Process interrupted. Exit code is " + exitCode, e);
        }
  
        this.completeLatch.countDown();
  
        // try to wait for everything to get logged out before exiting
        outputGobbler.awaitCompletion(5000);
        errorGobbler.awaitCompletion(5000);
  
        if (exitCode != 0) {
          throw new ProcessFailureException(exitCode);
        }
  
      } finally {
        IOUtils.closeQuietly(this.process.getInputStream());
        IOUtils.closeQuietly(this.process.getOutputStream());
        IOUtils.closeQuietly(this.process.getErrorStream());
      }
    }
docs: Execute this process, blocking until it has completed.