1、前言:
最近在做一个需求需要调用linux下的某个脚本来对ai的模型进行训练,很简单的需求,我像往常一样写下如下的代码片段:
Process process = Runtime.getRuntime().exec(cmd);
process.waitFor();
But当我运行代码时,发现代码执行到waitFor后阻塞住了,我以为这也许是训练模型需要时间,毕竟是同步阻塞的方法,那我就等一会吧!
一分钟……两分钟……10分钟……
我渐渐的意识到,这TM不对劲啊!
于是我通过以下命令查询了下linux执行情况。
ps aux |grep xxx.sh
输出的结果显示该脚本当前还在运行,而脚本的日志并没有从inputstream进行输出。我渐渐的慌了!
2 问题分析
2.1 观看JDK文档
根据查看JDK的文档,我看到Process.waitFor可能导致死锁?!仔细观看JDK的文档说明,发现文档上已经对死锁的情况进行了分析。
如果InputStream使用的buffer缓冲区有限的话,可能会导致阻塞和死锁 。
2.2 死锁原因
经过查阅资料,发现
- 当我们使用Runtime.exec执行命令时,JAVA的线程会创建一个子进程,用于执行命令,而且子进程和JAVA线程会分别独立运行。
- JAVA线程需要等待命令的执行完成,对命令的日志和返回值进行处理,所以我们在JAVA线程中调用Process.waitFor挂起来等待子进程完成。
- 子进程执行时,不断的打印日志信息,我们通过Process.getInputStream和Process.getErrorStream进行获取正常输出日志和错误日志进行处理。
- 这个时候子进程不断的向JAVA线程写入数据,而JAVA线程调用Process.waitFor后已经阻塞挂起,而子进程在不断的向JAVA线程进行写入数据,当我们的Process.getInputStream的buffer缓冲区被写满,而JAVA线程依然挂起并未消费buffer

在尝试使用Java的Runtime.exec执行Linux脚本时,遇到代码在waitFor方法处阻塞的问题。分析发现可能由输入流缓冲区满导致死锁。解决方案是通过多线程及时消费输入流数据,避免子进程和Java线程相互等待导致的死锁状态。
最低0.47元/天 解锁文章
707





