1. 程式人生 > >Runtime.getRuntime().exec執行阻塞問題解決

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();
}
 
        }  
    }  
}