Rhys
Rhys

Reputation: 1491

Runtime.exec().waitFor() not actually waiting for

I've got some code that uses Runtime.exec() to run an external .jar (built as an IzPack installer).

If I run this external.jar from the command line like so:

java -jar external.jar

Then the command prompt does not return control until the application is finished. However, if I run external.jar from within some java class, using:

Process p = Runtime.getRuntime().exec("java -jar external.jar");
int exitCode = p.waitFor();
System.out.println("Process p returned: " + exitCode);

Then p returns almost instantly with a success code of 0, despite external.jar having not yet completed execution (i've also tried this via the ProcessBuilder route of external file execution).

Why does it wait to return from the command line, but not when executed from within another java program?

I've also set up 3 jars, A, B and C where A calls B which calls C (using Runtime.exec()), where C Thread.sleeps for 10 seconds, as a simple test, and as expected, A doesn't return until 10 seconds after it runs.

I figure this is probably some kind of a threading issue with external.jar where execution is being handed over from one thing to another, but given that it works directly from the command line i kind of expected to see the same behaviour (perhaps naively) when called from within another java program.

I've tested this on Windows and Ubuntu with Java 6.

Thanks!

Upvotes: 13

Views: 29606

Answers (5)

antonio_Developer
antonio_Developer

Reputation: 517

another possible way to achieve this might be to capture the output of the process and wait for it to finish.

For example:

Process tr = Runtime.getRuntime().exec( new String[]{"wkhtmltopdf",mainPage,mainPagePDF});
BufferedReader stdOut=new BufferedReader(new InputStreamReader(tr.getInputStream()));
String s;
while((s=stdOut.readLine())!=null){
       //nothing or print
}

Normally the output stream is tr.getInputStream() but depending on the program you are executing the process output stream migh be:

  • tr.getInputStream()
  • tr.getErrorStream()
  • tr.getOutputStream()

By doing this while loop you force your program to wait the process to finish.

Upvotes: 7

Vishal Bhosale
Vishal Bhosale

Reputation: 11

You can use Process Builder....

ProcessBuilder pb = new ProcessBuilder("java", "-jar", "/fielname.jar");
Process p = pb.start();
p.waitFor();

Upvotes: 1

antonio_Developer
antonio_Developer

Reputation: 517

I had the same problem using processs to execute some software using the console, and i just solved it using process.waitFor()

For me it worked perfectly.

    try{
        Process tr = Runtime.getRuntime().exec( new String[]{ "wkhtmltopdf",frontPage,frontPagePDF});
        tr.waitFor();
    } catch (Exception ex) {
        EverLogger.logEntry("Error al pasar a PDF la portada", "error", "activity");
        return;
    } 
some more code here.

Upvotes: -2

Martin Jiang
Martin Jiang

Reputation: 19

Process.waitFor() is useless for some native system command.

You need to get the process's output to determine if it is returned.

I wrote a sample code for you

/**
 * 
 * @param cmdarray      command and parameter of System call
 * @param dir           the directory execute system call
 * @param returnImmediately   true indicate return after system call immediately; 
     *                          false otherwise.
 *  if set true, the returned call result does not have reference value
 * @return the return code of system call , default is -1
 */
public static int systemCall(String[] cmdarray,File dir,boolean returnImmediately)
{
  int result = -1;
  try {
   Process p = Runtime.getRuntime().exec(cmdarray,null,dir);
  if(!returnImmediately)
  {
   java.io.InputStream stdin = p.getInputStream();
   java.io.InputStreamReader isr = new java.io.InputStreamReader(stdin);
   java.io.BufferedReader br = new java.io.BufferedReader(isr);
   String line = null;
   while ( (line = br.readLine()) != null)
      System.out.println(line);
      }
      try{result =  p.exitValue();}
        catch(Exception ie){;}
      } catch (IOException e) {
        e.printStackTrace();}

  return result;
}

public static void main(String[] argc){             
  String[] cmdarray = {"jar","cvf","s2.jar","*"};
  File dir = new File("D:\\src\\struts-2.3.1");
  int k = systemCall(cmdarray,dir,true);
  System.out.println("k="+k);
 }

Upvotes: -1

Matt Westlake
Matt Westlake

Reputation: 3651

Are you spawning a new thread to handle the spawning of the process? If so the origional program will continue to operate independently of the spawned process and therefore waitFor() will only work on the new process and not the parent.

Upvotes: 0

Related Questions