Java中Process類的使用與註意事項說明
Process類的使用與註意事項說明
1、在項目開發中
經常會遇到調用其它程序功能的業務需求,在java中通常有兩種實現方法
Runtime runtime = Runtime.getRuntime(); Process p = runtime.exec(cmd);
Process p=new ProcessBuilder(cmd).start();
2、在這裡就需要認識一下process類
process是一個抽象的類,它包含6個抽象的方法
abstract public OutputStream getOutputStream(); abstract public InputStream getInputStream(); abstract public InputStream getErrorStream(); abstract public int waitFor() throws InterruptedException; abstract public int exitValue(); abstract public void destroy();
process類提供獲取子進程的輸入流、子進程的輸出流、子進程的錯誤流、等待進程完成、檢查進程的推出狀態以及銷毀進程的方法;在這裡需要提及的是創建的子進程沒有自己的控制臺或終端,其所有的io操作都是通過(輸入流、輸出流、錯誤流)重定向到父進程中。
3、來說說今天業務需求[waitfor()]:
我需要在linux下首先將一個文件copy到指定的文件夾下面,之後需要將該文件夾下面的文件加入指定的jar中,那麼問題就來瞭,必須保證其先後順序,也就書說再執行第二個命令的時候第一個命令必須完成。
public void cmd(String cmd){ try { Process ps= Runtime.getRuntime().exec(cmd); } catch (Exception e) { logger.info(e.getMessage(),e); } }
main函數如下:
public static void main(String[] args){ String copy="cp -rf "+source+" "+target; String jar="jar -uvf "+jar+" "+file; cmd(copy); cmd(jar); }
但是結果是新生成的jar中壓根沒有新加入的文件,但是文件確實copy到瞭指定的文件夾中,也就是誰兩個命令都執行瞭,問題的關鍵就是“異步”,這時候需要waitFor()的介入
public void cmd(String cmd){ try { Process ps= Runtime.getRuntime().exec(cmd); ps.waitFor(); } catch (Exception e) { logger.info(e.getMessage(),e); } }
那麼問題就解決瞭!
4、前不久遇到一個奇怪的問題就是ajax調用沒有返回值
我在service中實現瞭process的調用。
String[] commands = { commandGenerate,commandPublish}; PrintWriter printWriter = response.getWriter(); for (String comm : commands) { Runtime runtime = Runtime.getRuntime(); try { logger.info("command is :{}",comm); Process process = runtime.exec(comm, null, null); BufferedInputStream inputStream = new BufferedInputStream( process.getInputStream()); BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(inputStream)); String line; while (bufferedReader.read() != -1) { line = bufferedReader.readLine(); System.out.println(line); } bufferedReader.close(); inputStream.close(); printWriter.println("success"); } catch (IOException e) { logger.error(e.getMessage(), e); printWriter.println(e.getMessage()); } } printWriter.flush(); printWriter.close();
對應的controller為:
State state = new State(); String message=""; try { message = missionService.syntax(taskName, response); } catch (InterruptedException e) { e.printStackTrace(); } state.setSuccess(true); state.setMessage(message.trim()); return state;
打印state.getMessage()確實可以獲得值,但是state返回就是空,剛開始以為是ajax的timeout時間的問題:修改瞭ajax的timeout時間仍然不行;將message直接賦值,然thread等待20s,結果是可以返回的,所以問題最終定為於service的這段實現。
原因分析:在上面提及瞭,process創建的子進程沒有自己的控制臺或終端,其所有的io操作都是通過(輸入流、輸出流、錯誤流)重定向到父進程中,如果該可執行程序的輸入、輸出或者錯誤輸出比較多的話,而由於運行窗口的標準輸入、輸出等緩沖區有大小的限制,則可能導致子進程阻塞,甚至產生死鎖,其解決方法就是在waitfor()方法之前讀出窗口的標準輸出、輸出、錯誤緩沖區中的內容。
for (String comm : commands) { logger.info("the comm time is:"+new Date().getTime()+" the comm is:"+comm); Runtime runtime = Runtime.getRuntime(); Process p=null; try { p = runtime.exec(comm ,null,null); final InputStream is1 = p.getInputStream(); final InputStream is2 = p.getErrorStream(); new Thread() { public void run() { BufferedReader br1 = new BufferedReader(new InputStreamReader(is1)); try { String line1 = null; while ((line1 = br1.readLine()) != null) { if (line1 != null){ logger.info("p.getInputStream:"+line1); if(line1.indexOf("syntax check result:")!=-1){ builder.append(line1); } } } } catch (IOException e) { e.printStackTrace(); } finally{ try { is1.close(); } catch (IOException e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { BufferedReader br2 = new BufferedReader(new InputStreamReader(is2)); try { String line2 = null ; while ((line2 = br2.readLine()) != null ) { if (line2 != null){ } } } catch (IOException e) { e.printStackTrace(); } finally{ try { is2.close(); } catch (IOException e) { e.printStackTrace(); } } } }.start(); p.waitFor(); p.destroy(); } catch (Exception e) { try{ p.getErrorStream().close(); p.getInputStream().close(); p.getOutputStream().close(); } catch(Exception ee){} } }
java的Process深入講解
package cn.itcast.process; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; public class ProcessTest implements Runnable{ private Process process = null; public ProcessTest() { try { process = Runtime.getRuntime().exec("java MyTest"); new Thread(this).start(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { ProcessTest processTest = new ProcessTest(); processTest.send(); } public void send() { OutputStream outputStream = process.getOutputStream(); while(true) { try { outputStream.write("this is good\r\n".getBytes()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void run() { InputStream inputStream = process.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String str = null; try { while(true) { str = bufferedReader.readLine(); System.out.println(str); } } catch (IOException e) { e.printStackTrace(); } } }
//理解下面這句話就能更加容易的理解上面的代碼
在java程序中可以用Process類的實例對象來表示子進程,子進程的標準輸入和輸出不在連接到鍵盤和顯示器,而是以管道流的形式連接到父進程的
一個輸出流和輸入流對象上-à好好理解這句代碼就能看懂那個程序。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Java Process與Runtime()的使用及調用cmd命令阻塞的解決方案
- 基於Process#waitFor()阻塞問題的解決
- 使用Runtime 調用Process.waitfor導致的阻塞問題
- 解決Process.getInputStream()阻塞的問題
- java.lang.Runtime.exec的左膀右臂:流輸入和流讀取詳解