Linux中Java后端调用外部进程 未处理后台输出流 导致io阻塞问题解决方法
问题复现
项目中遇到通过Java后端调用启动CMake编译好的C++二进制文件,Websocket 客户端与服务端正常建立连接通信约两分钟后服务端会失联的问题,但如果本地启动C++进程通信是正常的。
问题原因
服务端启动C++进程的方法是通过:
ProcessBuilder pb = new ProcessBuilder("bash","-c","/home/ubuntu/cmake bin文件; exec bash");
然而ProcessBuilder
如果只启动进程,但未处理输出流会造成io阻塞,因为没有正确处理外部进程(算法)的输出流,因此关于本地回环通信以及日志模块的功能都会受到影响。
- ProcessBuilder(“./my_cpp_program”).start() 启动外部进程
- 必须处理 process.getInputStream() 和 process.getErrorStream()
- 否则C++进程的输出会阻塞,导致WebSocket子线程无法接收消息
- 这是Unix/Linux系统的进程间通信机制决定的,不是Java或C++的bug
解决方法
方法一
直接丢弃输出流,防止有限缓冲区造成io阻塞
Process process = pb
// 丢弃stdout
.redirectOutput(ProcessBuilder.Redirect.DISCARD)//丢弃stderr
.redirectError(ProcessBuilder.Redirect.DISCARD).start();
方法二
使用Commons Exec
进行外部进程管理
Commons Exec是为了简化 Java 应用中外部进程的调用和管理而设计的。它通过封装 Java 原生的 Process 和 Runtime,提供了更加友好和强大的API。这个库的设计重点是易用性和灵活性,让开发者可以更加专注于业务逻辑,而不是纠结于底层的进程管理细节。