1. 程式人生 > 實用技巧 >Process.waitFor() 死鎖問題了解和解決

Process.waitFor() 死鎖問題了解和解決

ProcessBuilder pb = new ProcessBuilder("C:\\Debug\\TestRedis.exe", keyNmae);
pb.redirectErrorStream(true);
Process process = pb.start();
//可能導致程序阻塞,甚至死鎖
int ret = process.waitFor();

1、waitFor問題描述分析

1、 主程序中呼叫pb.start會建立一個子程序,用於執行shell /exe 指令碼。子程序建立後會和主程序分別獨立執行。
2.、因為主程序需要等待指令碼執行完成,然後對指令碼返回值或輸出進行處理,所以這裡主程序呼叫process.waitFor

()等待子程序完成。

3.、程序執行過程就是不斷的列印資訊。主程序中可以通過Process.getInputStream和Process.getErrorStream獲取並處理。
4.、這時候子程序不斷向主程序發生資料,而主程序呼叫Process.waitfor後已掛起。當前子程序和主程序之間的緩衝區塞滿後程序不能繼續寫資料,然後也會掛起
5.、這樣子程序等待主程序讀取資料,主程序等待子程序結束,兩個程序相互等待,最終導致死鎖。

2、解決死鎖問題

基於上述分析,只要主程序在waitFor之前,能不斷處理緩衝區中的資料就可以。因為,我們可以再waitfor之前,單獨啟2個額外的執行緒,分別用於處理InputStream和ErrorStream就可以

                try (
                        InputStream inputStream = process.getInputStream();
                        InputStream inputErrorStream = process.getErrorStream();
                ) {
                    // 讀取Shell的輸出內容,並新增到string中:
                    //啟動兩個執行緒,一個執行緒負責讀標準輸出流,另一個負責讀標準錯誤流
new Thread(() -> { try { val msg = IOUtils.toString(inputStream, StandardCharsets.UTF_8); response.setShellOutput(msg); } catch (Exception e) { log.error(e.getMessage(), e); } }).start(); new Thread(() -> { try { var errMsg = IOUtils.toString(inputErrorStream, StandardCharsets.UTF_8); response.setShellErrorOutput(errMsg); } catch (Exception e) { log.error(e.getMessage(), e); } }).start(); process.waitFor(2, TimeUnit.HOURS);////可能導致程序阻塞,甚至死鎖 int exitCode = process.exitValue();// response.setSuccessful(exitCode == SHELL_EXIT_CODE_SUCCESS); }