为什么 process.waitFor() 没有返回?

Why process.waitFor() is not returning?

我正在尝试使用 Runtime.getRuntime().exec 执行任务。

符合预期

我正在控制台中“开始任务”。 任务被执行并完成。

问题

从未打印过“任务完成”。

你知道可能是什么原因吗?或者我该如何处理?

代码

System.out.println("task started");
Process process = Runtime.getRuntime().exec("cmd.exe /c task.bat task.job");
process.waitFor();
System.out.println("task completed");

为什么 process.waitFor() 没有返回?

根据 class Process 的 JavaDoc,某些平台的输出缓冲区有限:

All its standard I/O (i.e. stdin, stdout, stderr) operations [..] can be accessed via [..] getOutputStream(), getInputStream(), and getErrorStream(). Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock.

在调用 process.waitFor() 之前尝试以下操作:

  1. 使用 getErrorStream() and getOutputStream()
  2. 从进程中获取 output-streams
  3. 读取它们的内容以刷新缓冲区

exec 命令正在 returning 一个 process-handle(就像 PID)。

如果进程已经终止,你可以查询它的exit-value process.exitValue() 作为 int:

By convention, the value 0 indicates normal termination.

否则如果进程还在运行:

IllegalThreadStateException - if the subprocess represented by this Process object has not yet terminated

waitFor()也一样:

This method returns immediately if the subprocess has already terminated. If the subprocess has not yet terminated, the calling thread will be blocked until the subprocess exits.

由于阻塞不是你可能想要的,可以在这里设置一个超时,然后 return of waitFor(long, TimeUnit) 改变。

因此您可以包裹在 try-catch 块中以获得完全控制:

Process process = null;
System.out.println("Task will start soon ..");
try {
    process = Runtime.getRuntime().exec("cmd.exe /c task.bat task.job");
    System.out.println("Task started.");
    boolean alreadyTerminated = process.waitFor(50L, TimeUnit.SECONDS);  // you can also set a timeout
    if (!alreadyTerminated)
        System.out.println("Task still executing. Will wait for 50 seconds.");
    int exitValue = process.exitValue();
    System.out.println("Task completed with exit-code: " + exitValue);
} catch (IllegalThreadStateException e) {
    System.out.println(e);
}

问题可能是您应该读取所​​有输出(标准和错误,以便该进程可以退出)

所以,您可能需要这样做

final ProcessBuilder processBuilder = new ProcessBuilder("cmd.exe", "/c", "task.bat", "task.job");

// if you want process output to be printed by you program
processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);

// if you don't want to show anything
// processBuilder.redirectError(ProcessBuilder.Redirect.DISCARD);
// processBuilder.redirectOutput(ProcessBuilder.Redirect.DISCARD);

Process process = processBuilder.start();
int exitCode = process.waitFor();
System.out.println(exitCode);