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更直觀易懂。