1. 背景
系统上线后,准备通过logQuery进行计算,并检验数据是否准确,但程序计算1w左右时停止。
2. 分析
系统运行原理
系统通过logQuery系统执行Runtime方法调用shell脚本启动java补货计算系统。
问题分析
在系统死锁时,通过jstack观察jvm中所有线程运行情况和线程状态。
发现有一个线程处于runnable状态并locked了log4j的callAppenders方法和doAppend方法,由于callAppenders和doAppend中含有synchronized,所以导致其他线程死锁。
继续进行测试及分析,发现直接运行shell脚本进行补货计算没有发生死锁问题,所以可以排除shell脚步及计算程序问题。
于是将问题集中到logQuery代码中,通过大量的测试及百度搜索,最终将问题缩小到Runtime方法的Process返回类型中。
查看JAVA API:
大喜,问题估计找到了。
系统死锁时代码结构
串行运行,需要 errorBr流全部输出完毕后,才会输出br流程中信息。可能会导致API中所描述的死锁。
随即写了一个多线程进行测试。
注意:代码后需要添加process.waitFor(),作用就是当前线程等待,直到所有子线程运行完毕。
至此补货系统线程阻塞问题解决。
3. 关于Ant对Runntime方法的使用
下载ant-source-1.7.1,导入到eclipse中。
进入org.apache.tools.ant.taskdefs.Exec.java中,查看protectedint run(String command) 方法。
窃喜,跟当初解决方案一样,都是多线程输出getInputStream和getErrorStream两个InputStream流。
不过值得注意的是:ant中使用了join及destroy,使代码更加完善。
Exec.java在ant1.2之后已经废弃不在维护,取而代之的是org.apache.tools.ant.taskdefs.Execute.java,Execute加强了对代码的抽象性和扩展性,但对于本次分析,使用Exec.java更直观易懂。