正常來說java調用shell命令就是用
String[] cmdAry = new String[]{"/bin/bash","-c",cmd}
Runtime.getRuntime().exec(cmdAry);
實際上就是創建個子進程去執行這個命令。
問題來了: 如果我執行下面這句命令
exp system/manager buffer=64000 file=/home/oracle/beifen/beifen.dmp FULL=Y
這種輸出日志量特別大的命令,就會出現卡死,一直不動,后來了解到 子進程產生的輸出日志都會寫到窗口里,因為窗口有緩存大小限制,
到達一定程度時就會卡死,導致死鎖,后來百度了其他作者的資料才發現,這種直接調用exec用法是不好的,數據量小可能體現不出來,
數據量大的時候 就會直接緩存爆滿 子進程就會卡死,所以我們可以創建2個線程來消費子進程運行shell命令產生的日志,正確用法如下
public class TestController { @GetMapping("/exp") public void addHomePage(String cmd) throws InterruptedException, IOException { //創建子進程調用shell命令 new MyThread(cmd).start(); } } class MyThread extends Thread { String cmd; MyThread(String cmd) { this.cmd = cmd; }
public void run(){ Process proc = null; try {
String[] cmdAry = new String[]{"/bin/bash","-c",cmd} proc = Runtime.getRuntime().exec(cmdAry); } catch (IOException e) { e.printStackTrace(); } //接收子進程的匯報信息和錯誤信息,避免阻塞 new StreamGobbler(proc.getInputStream(),"INFO").start(); new StreamGobbler(proc.getErrorStream(),"ERROR").start(); //獲取子進程執行結果狀態 int status= 0; try { status = proc.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } if (status == 0){ System.out.println("執行完畢"); }else System.out.println("執行失敗"); //銷毀子進程 proc.destroy(); } } class StreamGobbler extends Thread { InputStream is; String type; StreamGobbler(InputStream is, String type) { this.is = is; this.type = type; } public void run() { try { InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line=null; while ( (line = br.readLine()) != null) System.out.println(type + ">" + line); } catch (IOException ioe) { ioe.printStackTrace(); } } }
這樣就可以了 記得以后調用shell命令都用這種形式
