Process.waitFor()返回子进程退出码,0通常表示成功;必须先调用waitFor()再调用exitValue(),否则抛异常;需消费输入流防阻塞;destroy()不强制终止,destroyForcibly()才等效kill-9。

Process.waitFor() 返回值就是子进程退出码
Java 的 Process 对象本身不提供“返回值”概念,它只暴露子进程的退出状态——也就是操作系统层面的 exit code。调用 waitFor()(或带超时的重载)后,返回的 int 值就是这个退出码,0 通常表示成功,非 0 表示异常或业务错误。
常见错误是误以为 waitFor() 返回的是子进程 stdout 内容,或者试图在没调用它之前就读取退出状态——此时进程可能还在跑,exitValue() 会直接抛 IllegalThreadStateException。
- 必须先调用
waitFor()或确保进程已终止,才能安全调用exitValue() - 如果子进程卡死、挂起,
waitFor()会无限阻塞;生产环境务必用带超时的waitFor(long, TimeUnit) - 某些 shell 封装(如
/bin/sh -c "cmd1 && cmd2")失败时,退出码反映的是最后一条命令的结果,不是整个表达式逻辑结果
读取 stdout/stderr 必须配合流消费,否则 waitFor 可能假死
子进程输出缓冲区满时(尤其 C/C++ 程序默认行缓冲或全缓冲),会阻塞写入,进而导致子进程暂停——即使你只关心退出码,不读流也会让 waitFor() 永远不返回。
这不是 Java 的 bug,是 Unix 进程间通信的底层机制:管道缓冲区有限,不消费就堵死。
立即学习“Java免费学习笔记(深入)”;
- 哪怕只想要退出码,也必须启动线程或使用
InputStream.readAllBytes()(Java 9+)消费process.getInputStream()和process.getErrorStream() - 别用
Scanner或BufferedReader.readLine()在无界循环里等 EOF——子进程没关 stdout 流,你就永远等不到 - 推荐用
ProcessBuilder.inheritIO()调试时直连控制台;但生产中要显式处理流,避免僵尸输出
Windows 下 cmd.exe /c 和 PowerShell 启动方式影响 exit code 语义
在 Windows 上,直接执行 .exe 文件(如 notepad.exe)退出码由程序自身决定;但通过 cmd /c 或 powershell -c 启动命令链时,shell 自身的解析和执行逻辑会覆盖原始 exit code。
例如:cmd /c "dir nonexistent & echo done" 即使 dir 失败(exit 1),整个命令仍可能返回 0,因为 echo done 成功了。
- 用
cmd /c "command & exit /b %errorlevel%"显式透传上一条命令的%errorlevel% - PowerShell 中用
$LASTEXITCODE,但需注意:非 native 命令(如 cmdlet)不设它,只有Start-Process -Wait启动的外部程序才更新该变量 - 跨平台脚本建议统一用
sh -c+set -e,或改用ProcessBuilder.redirectErrorStream(true)合并流后自行解析输出判断成败
Process.destroy() 不等于立即退出,destroyForcibly() 才接近 kill -9
destroy() 发送的是 SIGTERM(Unix)或 CTRL_BREAK_EVENT(Windows),子进程可以捕获并忽略;而 destroyForcibly()(Java 8+)才等效于 SIGKILL 或 TerminateProcess,无法被捕获。
这意味着:调用 destroy() 后立刻 waitFor(),可能长时间等待,甚至永远等不到退出码——因为进程正在优雅关闭,或根本没响应信号。
- 超时后必须用
destroyForcibly(),再等一次,否则进程残留成孤儿 -
isAlive()比检查exitValue()异常更安全,但注意它只反映 OS 层面是否还存在,不保证资源已释放完毕 - Linux 下可配合
/proc/<pid>/stat</pid>验证进程是否真消亡;Java 层无直接 API,需 shell 辅助
退出码只是表层信号,真正难的是判断“进程到底算不算成功结束”——比如子进程写了临时文件但中途崩溃,或 stdout 输出了 “success” 字样却以非零退出。这些边界情况没法靠 Process 自身解决,得结合日志、文件状态、网络端口等外部证据交叉验证。










