java的ProcessBuilder阻塞问题

<span style="color: #464646; font-family: simsun; font-size: 14px; line-height: 21px; background-color: #f8ecd8;">使用ProcessBuilder类,利用redirectErrorStream方法将标准输出流和错误输出流合二为一,在用start()方法启动进程后,先从标准输出中读取数据,然后调用waitFor()方法等待进程结束</span>
JavaProcessBuilder创建的Process对象的destroy方法无效,可能存在以下原因及对应的解决办法: ### 原因 - **缓冲区阻塞**:ProcessBuilder中的流是阻塞的,会使用一个缓冲区来存储子进程的输出。如果子进程的输出数据量占满了缓冲区,可能会导致线程挂起或阻塞,使得destroy方法无法正常工作[^1]。 - **系统兼容性问题**:不同的操作系统对进程销毁的处理方式可能不同,某些情况下可能导致destroy方法无法有效终止子进程。 - **子进程特性**:一些子进程可能有自己的守护进程或子进程,destroy方法可能只能终止直接的子进程,而无法终止其衍生的子进程。 ### 解决办法 - **合并输出流**:可以将标准输出和错误输出合并,避免缓冲区阻塞问题。使用`builder.redirectErrorStream(true)`来实现这一点[^1][^2]。 ```java ProcessBuilder builder = new ProcessBuilder("Python", command); builder.redirectErrorStream(true); ``` - **Java 9及以上版本**:使用`ProcessHandle`来销毁进程及其子进程。`ProcessHandle`提供了更强大的进程管理功能,可以销毁直接子进程和间接子进程。 ```java ProcessHandle handle = p.toHandle(); handle.destroy(); handle.descendants().forEach(ProcessHandle::destroy); ``` - **Java 8及以下版本**:可以通过反射获取进程的PID,然后使用系统命令来杀死进程树。以下是示例代码,既能杀死`sudo`进程,又能杀死`python`进程: ```java try { Process process = Runtime.getRuntime().exec(cmd); java.lang.reflect.Field f = process.getClass().getDeclaredField("pid"); f.setAccessible(true); long handl = f.getLong(process); if (!process.waitFor(100, java.util.concurrent.TimeUnit.SECONDS)) { String cmd2 = "kill -SIGTERM " + String.valueOf(handl); Process process2 = Runtime.getRuntime().exec(cmd2); if (!process.waitFor(100, java.util.concurrent.TimeUnit.SECONDS)) { process2.destroyForcibly(); } else { System.out.println("kill success"); } throw new Exception("exec Timeout"); } else { System.out.println("exec success"); } } catch (Exception e) { throw e; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值