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

Java Runtime.exec().waitFor()实际上没有等待,java,multithreading,runtime.exec,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(); S

我有一些代码使用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个JAR,A、B和C,其中A调用B调用C(使用
Runtime.exec()
),其中C
Thread.sleep
s持续10秒,作为一个简单的测试,正如预期的那样,A在运行10秒后才会返回

我认为这可能是external.jar的线程问题,执行从一件事转移到另一件事,但考虑到它直接从命令行工作,我有点希望在从另一个java程序调用时看到相同的行为(可能很幼稚)

我已经用Java6在Windows和Ubuntu上测试过了


谢谢

您是否正在生成一个新线程来处理进程的生成?如果是这样,原始区域程序将继续独立于生成的进程运行,因此waitFor()将只在新进程上工作,而不在父进程上工作。

进程。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);
 }

我使用processs在控制台上执行一些软件时遇到了同样的问题,我只是使用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.

实现这一点的另一种可能的方法是捕获流程的输出并等待它完成

例如:

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()

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

您可以使用process Builder

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

据我所知,
whatFor()
将等待您启动的进程结束,这意味着所有非守护进程线程都已完成,因此我怀疑这是否仅仅是线程问题。我想知道你调用的jar本身是否调用了一个外部进程然后退出。你怎么知道它还没有完成?您仍然在进程列表中看到jar吗?这不太可能,有没有可能其他线程正在您的
process
字段上调用
notify()
?这就是
waitFor()
UNIXProcess
中所做的,至少.external.jar生成了一个自己的控制台窗口,然后该窗口运行在自己的各种
System.out.println
中,记录其执行过程。当返回退出代码时,这个日志记录仍然在继续(另外,我知道做任何事情都需要30秒左右,而返回几乎是瞬时的)。也许这与气垫船的建议有关?格雷-
进程p
完全独立于一个方法调用中,除了上面描述的之外,它不做任何其他事情,因此没有其他与它的交互。不,这一切都发生在一个线程中,即,我可以在调用方法中
线程。睡眠
,让我的应用程序睡眠,这就是我目前正在做的工作,通过睡眠来解决这个问题,直到满足某些外部参数(如现有的某些文件)。不过,这并不理想。“对于某些本机系统命令来说是无用的”它还有什么用途?您的开始争论需要一些支持证据或推理,而您的代码是错误的,因为您没有使用进程的错误流;您没有关闭它的输入流;如果进程尚未退出,则忽略exitValue()引发的异常-这对我来说确实有效。waitFor()立即返回(例如,因为主线程已结束),但只要进程未完全终止,流将保持可访问状态。无法使用输入和错误流不会导致挂起吗?