Runtime.exec()。waitFor()实际上并没有等待

时间:2012-07-05 18:28:15

标签: java multithreading runtime.exec

我有一些代码使用Runtime.exec()运行外部.jar(构建为IzPack安装程序)。

如果我从命令行运行这个external.jar,如下所示:

java -jar external.jar

然后,在应用程序完成之前,命令提示符不会返回控件。但是,如果我从某个java类中运行external.jar,请使用:

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

然后p几乎立即返回,成功代码为0,尽管external.jar尚未完成执行(我也通过外部文件的ProcessBuilder路径尝试了此操作执行)。

为什么它等待从命令行返回,但是在从另一个java程序执行时却没有?

我还设置了3个罐子,A,B和C,其中A调用B调用C(使用Runtime.exec()),其中C Thread.sleep为10秒,作为一个简单的测试,正如预期的那样,A在运行10秒后才会返回。

我认为这可能是external.jar的某种线程问题,其中执行是从一件事移交给另一件事,但鉴于它直接从命令行工作,我希望看到相同的行为(从另一个java程序中调用时,可能是天真的。

我在Windows和Ubuntu上使用Java 6测试了这个。

谢谢!

5 个答案:

答案 0 :(得分:6)

另一种可能的方法是捕获进程的输出并等待它完成。

例如:

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
}

通常输出流是tr.getInputStream(),但是根据你正在执行的程序输出流,可能是:

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

通过执行此循环,您可以强制程序等待该过程完成。

答案 1 :(得分:1)

您可以使用Process Builder ....

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

答案 2 :(得分:0)

您是否正在产生一个新线程来处理该过程的产生?如果是这样,原始程序将继续独立于生成的进程运行,因此waitFor()仅适用于新进程而不是父进程。

答案 3 :(得分:-1)

Process.waitFor()对于某些本机系统命令没用。

您需要获取进程的输出以确定它是否已返回。

我为你写了一个示例代码

/**
 * 
 * @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);
 }

答案 4 :(得分:-1)

我使用进程使用控制台执行某些软件时遇到了同样的问题,我只是使用process.waitFor()

来解决它

对我而言,它完美无缺。

    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.