Linux下Java Process InputStream无输出问题排查
问题排查:ProcessBuilder执行lsof无输出的原因
以下是几个容易忽略的细节及解决方法:
1. 未处理错误输出流导致进程阻塞
ProcessBuilder启动的子进程,标准输出(stdout)和错误输出(stderr)是两个独立的缓冲区。终端中默认会将两者合并打印,所以你看不到区别;但Java代码里如果只读取stdout,当stderr缓冲区被填满时,子进程会被阻塞,无法继续向stdout输出内容。
解决方法:将stderr合并到stdout,或者单独开启线程读取stderr:
// 合并stderr到stdout,统一读取 builder.redirectErrorStream(true);
2. 未等待进程执行完成就销毁
你的代码在读取完输出后调用process.destroy(),但如果进程还未完全执行完毕,readLine()可能提前返回null,导致你错过输出。建议先等待进程执行结束:
// 等待进程执行完成,获取退出码 int exitCode = process.waitFor();
3. 运行权限不匹配
终端执行命令的用户与Java进程运行的用户权限可能不同。比如终端用root用户能正常获取PID,但Java进程以普通用户运行时,lsof会因权限不足向stderr输出错误信息,进而导致进程阻塞无输出。
可以检查Java进程的运行用户,或者尝试用sudo执行命令(需确保Java进程有sudo权限)。
4. 进程名称匹配不准确
终端中TestJar.jar可能是进程的短名称,但实际进程名可能包含完整路径。可以用以下命令确认进程的真实名称:
lsof -t -c java | xargs ps -p -o cmd=
如果是路径问题,修改lsof命令为精确匹配路径:
/usr/sbin/lsof -t /full/path/to/TestJar.jar
修改后的示例代码
try { ProcessBuilder builder = new ProcessBuilder("bash", "-c", "/usr/sbin/lsof -t TestJar.jar"); builder.redirectErrorStream(true); // 合并错误输出到标准输出 Process process = builder.start(); // 等待进程执行完成 int exitCode = process.waitFor(); System.out.println("进程退出码: " + exitCode); System.out.println("----------------"); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while((line = reader.readLine()) != null) { System.out.println(line); } reader.close(); process.destroy(); System.out.println("----------------"); } catch(Exception e) { System.out.println("FAILED"); Main.printToErrorLog(e); }
内容的提问来源于stack exchange,提问作者M. Rogers
相关产品推荐
相关产品推荐

