Runtime.getRuntime().exec執行阻塞問題解決
有時候我們可能需要呼叫系統外部的某個程式,此時就可以用Runtime.getRuntime().exec()來呼叫,他會生成一個新的程序去執行呼叫的程式。
此方法返回一個java.lang.Process物件,該物件可以得到之前開啟的程序的執行結果,還可以操作程序的輸入輸出流。
Process物件有以下幾個方法:
1、destroy() 殺死這個子程序
2、exitValue() 得到程序執行結束後的返回狀態
3、waitFor() 得到程序執行結束後的返回狀態,如果程序未執行完畢則等待知道執行完畢
4、getInputStream() 得到程序的標準輸出資訊流
5、getErrorStream() 得到程序的錯誤輸出資訊流
6、getOutputStream() 得到程序的輸入流
現在來講講exitValue(),當執行緒沒有執行完畢時呼叫此方法會跑出IllegalThreadStateException異常,最直接的解決方法就是用waitFor()方法代替。
但是waitFor()方法也有很明顯的弊端,因為java程式給程序的輸出流分配的緩衝區是很小的,有時候當程序輸出資訊很大的時候回導致緩衝區被填滿,如果不及時處理程式會阻塞。如果程式沒有對程序的輸出流處理的會就會導致執行exec()的執行緒永遠阻塞,程序也不會執行下去直到輸出流被處理或者java程式結束。
解決的方法就是處理緩衝區中的資訊,開兩個執行緒分別去處理標準輸出流和錯誤輸出流。
處理方法:
Process p = Runtime.getRuntime().exec(cmdStr);
//用於處理Runtime.getRuntime().exec產生的錯誤流及輸出流 ,防止阻塞
StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "ERROR");
errorGobbler.start();
StreamGobbler outGobbler = new StreamGobbler(p.getInputStream(), "STDOUT");
outGobbler.start();
p.waitFor();
StreamGobbler.java
package cn.rojao.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
/**
* 用於處理Runtime.getRuntime().exec產生的錯誤流及輸出流
*
*/
public class StreamGobbler extends Thread {
InputStream is;
String type;
OutputStream os;
public StreamGobbler(InputStream is, String type) {
this(is, type, null);
}
StreamGobbler(InputStream is, String type, OutputStream redirect) {
this.is = is;
this.type = type;
this.os = redirect;
}
public void run() {
InputStreamReader isr = null;
BufferedReader br = null;
PrintWriter pw = null;
try {
if (os != null)
pw = new PrintWriter(os);
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null) {
if (pw != null)
pw.println(line);
System.out.println(type + ">" + line);
}
if (pw != null)
pw.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally{
pw.close();
try {
br.close();
isr.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}