java調用第三方命令,process.waitfor()掛起(你不知道的坑)


我們常在java中運行第三方程序,如sh、python,java提供一個Runtime.exec()方法,生成一個Process對象。今天在使用這個方法的時候,發現接口半天沒有返回數據。查了一下,原來還有這樣的一個坑。記錄一下

代碼是網上的,見如下。

 public static String execCmd(String cmd, File dir) throws Exception {
        StringBuilder result = new StringBuilder();

        Process process = null;
        BufferedReader bufrIn = null;
        BufferedReader bufrError = null;

        try {
            // 執行命令, 返回一個子進程對象(命令在子進程中執行)
            process = Runtime.getRuntime().exec(cmd, null, dir);

            // 方法阻塞, 等待命令執行完成(成功會返回0)
            process.waitFor();

            // 獲取命令執行結果, 有兩個結果: 正常的輸出 和 錯誤的輸出(PS: 子進程的輸出就是主進程的輸入)
            bufrIn = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            bufrError = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));

            // 讀取輸出
            String line = null;
            while ((line = bufrIn.readLine()) != null) {
                result.append(line).append('\n');
            }
            while ((line = bufrError.readLine()) != null) {
                result.append(line).append('\n');
            }
    return result
}

執行后,一直沒有輸出。原因如下:

1. 主進程中調用Runtime.exec會創建一個子進程,用於執行shell腳本。子進程創建后會和主進程分別獨立運行。

2. 因為主進程需要等待腳本執行完成,然后對腳本返回值或輸出進行處理,所以這里主進程調用Process.waitfor等待子進程完成。

3. 通過shell腳本可以看出:子進程執行過程就是不斷的打印信息。主進程中可以通過Process.getInputStream和Process.getErrorStream獲取並處理。

4. 這時候子進程不斷向主進程發生數據,而主進程調用Process.waitfor后已掛起。當前子進程和主進程之間的緩沖區塞滿后,子進程不能繼續寫數據,然后也會掛起。

5. 這樣子進程等待主進程讀取數據,主進程等待子進程結束,兩個進程相互等待,最終導致死鎖

解決方案:

    開兩個線程在waitfor()命令之前讀出窗口的標准輸出緩沖區和標准錯誤流的內容。

 

        new Thread() {
            @Override
            public void run() {
                BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line = null;

                try {
                    while ((line = in.readLine()) != null) {
                        log.info("datax執行的結果為: "+line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run()
            {
                BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                String line = null;
                StringBuilder result=new StringBuilder();
                try
                {
                    while((line = err.readLine()) != null)
                    {
                        result.append(line);
                    }
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
                finally
                {
                    try
                    {
                        err.close();
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM