故障现象
Java调度系统创建PHP数据脚本后,并且获取其标准输出流,然后循环读取其标准输出流内容。此时PHP数据脚本执行时间过长,Java调度系统Process.destory()杀掉进程后,ps也无法找到对应PHP数据脚本,但Java的线程却无法退出,依然卡死在读取标准输出流。曾经怀疑是kill无法清理干净进程,于是变为强制执行kill -9杀掉超时的PHP数据脚本,但情况依旧,Java线程依然卡死。
Java创建PHP数据脚本的代码大致如下:
childProcess = Runtime.getRuntime().exec(cmd);
stream = childProcess.getInputStream();
while ((size = stream.read(bytes)) != -1) {
//处理输出流数据
}
//子进程退出
//...
故障分析
首先利用jstack找出对应线程堆栈,堆栈如下所示:
"TaskThread-CRON556" prio=10 tid=0x00007f4e38005800 nid=0x3563 runnable [0x00007f4f4167c000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:272)
......
可以发现线程卡死在java.io.FileInputStream.readBytes(Native Method)这个native方法中,查找对应的native代码,发现最终是linux的系统调用read方法。于是通过jstack上该线程对应的nid,0x3563转换10进制为13667 ,使用命令