前些天使用Java調用外部程序的時候
發現線程會堵塞在waitfor()方法
調用方法如下
Process process = Runtime
getRuntime()
exec(cmd)
process
waitfor()
如果直接在Shell中調用這個程序
程序會很快結束
不會僵死
為什麼會堵塞呢
原因是當調用exec(cmd)後
JVM會啟動一個子進程
該進程會與JVM進程建立
個管道連接
標准輸入
標准輸出和標准錯誤流
假設該程序不斷在向標准輸出流和標准錯誤流寫數據
而JVM不讀取
數據會暫時緩沖在Linux的緩沖區
緩沖區滿後該程序將無法繼續寫數據
會僵死
所以Java程序就會僵死在waitfor()
永遠無法結束
解決辦法就是增加兩個線程
一個線程負責讀標准輸出流
另一個負責讀標准錯誤流
這樣子數據就不會積壓在緩沖區
程序就能夠順利運行
查看源代碼後
還發現一個潛在的問題
但程序執行到exec的時候
JVM會使用管道
占有
個文件句柄
但程序運行結束後
這三個句柄並不會自動關閉
這樣最終會導致java
io
IOException: Too many open files
所以就算外部程序的沒有輸出
也必須關閉句柄
Process process=null;
try{
process = Runtime
getRuntime()
exec(cmd)
process
waitfor()
}cache{
process
getOutputStream()
close()
process
getInputStream()
close()
process
getErrorStream()
close()
}
我們發覺當調用close()方法後
JVM並不會立即回收句柄
具體的回收時間不確定
另外如果不調用close()
句柄也會被回收
也可能發生
Too many open files
的錯誤
根據這篇文章
不同的垃圾收集器會選擇不同的回收策略
所以最好還是要關閉
總結
如果外部程序有大量輸出
需要啟動額外的線程來讀取標准輸出和標准錯誤流
必須關閉三個句柄
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26495.html