最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java調(diào)用process線程阻塞問題的解決

 更新時間:2021年06月09日 08:35:59   作者:遺失的歲月  
這篇文章主要介紹了java調(diào)用process線程阻塞問題的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

java調(diào)用process線程阻塞問題

項目需求中涉及java調(diào)用.bat文件進行圖像處理,先直接上簡略版程序

public void draw(){
        //調(diào)用bat腳本進行圖像處理
        Process process = null;
        InputStream in = null;
        try {
            process = Runtime.getRuntime().exec("startup.bat");
            //輸出測試
//            in = process.getInputStream();
//            String line;
//            BufferedReader br = new BufferedReader(new InputStreamReader(in));
//            while ((line = br.readLine()) != null) {
//                System.out.println(line);
//            }
            //等待
            process.waitFor();
        } catch (Exception e) {
        } finally {
            process.destroy();
        }
    }

JAVA使用遇到的問題描述

一般需要調(diào)用系統(tǒng)命令時,大部分人第一反應肯定是使用Runtime.getRuntime().exec(command)返回一個process對象,再調(diào)用process.waitFor()來等待命令執(zhí)行結(jié)束,獲取執(zhí)行結(jié)果。

調(diào)試的時候發(fā)現(xiàn)異常現(xiàn)象,process.waitFor();一直沒有結(jié)束,導致線程阻塞再次,強行關(guān)閉程序后,發(fā)現(xiàn)圖像處理只進行了一部分。

根據(jù)現(xiàn)象并查看了JDK的幫助文檔,如下

如有必要,一直要等到由該 Process 對象表示的進程已經(jīng)終止。如果已終止該子進程,此方法立即返回。但是直接調(diào)用這個方法會導致當前線程阻塞,直到退出子進程。

對此JDK文檔上還有如此解釋:因為本地的系統(tǒng)對標準輸入和輸出所提供的緩沖池有效,所以錯誤的對標準輸出快速的寫入何從標準輸入快速的讀入都有可能造成子進程的阻塞,甚至死鎖。

Process執(zhí)行邏輯

* 主進程中調(diào)用Runtime.exec會創(chuàng)建一個子進程,用于執(zhí)行腳本。子進程創(chuàng)建后會和主進程分別獨立運行。

* 創(chuàng)建的子進程沒有自己的終端或控制臺。它的所有標準 io(即 stdin、stdout 和 stderr)操作都將通過三個流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父進程。父進程使用這些流來提供到子進程的輸入和獲得從子進程的輸出。

* 這時候子進程不斷向主進程發(fā)生數(shù)據(jù),而主進程調(diào)用Process.waitfor后已掛起。當前子進程和主進程之間的緩沖區(qū)塞滿后,子進程不能繼續(xù)寫數(shù)據(jù),然后也會掛起。

* 這樣子進程等待主進程讀取數(shù)據(jù),主進程等待子進程結(jié)束,兩個進程相互等待,最終導致死鎖。

解決方法:

在waitFor()之前,利用單獨兩個線程,分別處理process的getInputStream()和getErrorSteam(),防止緩沖區(qū)被撐滿,導致阻塞;

修改后代碼

public class test {
    public void draw(){
        //調(diào)用bat腳本進行圖像處理
        Process process = null;
        InputStream in = null;
        try {
            process = Runtime.getRuntime().exec("startup.bat");
            //輸出測試
//            in = process.getInputStream();
//            String line;
//            BufferedReader br = new BufferedReader(new InputStreamReader(in));
//            while ((line = br.readLine()) != null) {
//                System.out.println(line);
//            }
            //新啟兩個線程
            new DealProcessSream(process.getInputStream()).start();
            new DealProcessSream(process.getErrorStream()).start();
            process.waitFor();
        } catch (Exception e) {
        } finally {
            process.destroy();
        }
    }
}
public class DealProcessSream extends Thread {
    private InputStream inputStream;
    public DealProcessSream(InputStream inputStream) {
        this.inputStream = inputStream;
    }
    public void run() {
        InputStreamReader inputStreamReader = null;
        BufferedReader br = null;
        try {
            inputStreamReader = new InputStreamReader(
                    inputStream);
            br = new BufferedReader(inputStreamReader);
            // 打印信息
//            String line = null;
//            while ((line = br.readLine()) != null) {
//                System.out.println(line);
//            }
            // 不打印信息
           while (br.readLine() != null);
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }finally {
            try {
                br.close();
                inputStreamReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Process對象.waitFor()的阻塞問題(坑)

有時需要在程序中調(diào)用可執(zhí)行程序或腳本命令:

Process process = Runtime.getRuntime().exec(shPath);
int exitCode = process .waitFor();

Runtime.getRuntime()返回當前應用程序的Runtime對象,該對象的exec()方法指示Java虛擬機創(chuàng)建一個子進程執(zhí)行指定的可執(zhí)行程序,

并返回與該子進程對應的Process對象實例。通過Process可以控制該子進程的執(zhí)行或獲取該子進程的信息。

它的所有標準io(即stdin,stdout,stderr)操作都將通過三個流(getOutputStream(),getInputStream(),getErrorStream())重定向到父進程。

父進程使用這些流來提供到子進程的輸入和獲得從子進程的輸出。因為有些本機平臺僅針對標準輸入和輸出流提供有限的緩沖區(qū)大小,如果讀

寫子進程的輸出流或輸入流出現(xiàn)失敗,則可能導致子進程阻塞,甚至產(chǎn)生死鎖。(如果程序不斷在向標準輸出流和標準錯誤流寫數(shù)據(jù),而JVM不讀取的話,當緩沖區(qū)滿之后將無法繼續(xù)寫入數(shù)據(jù),最終造成阻塞在waifor()這里。)

process .getErrorStream():獲得子進程的錯誤輸出流

process .getInputStream():獲得子進程的普通輸出流

簡單示例:

Process shellProcess = null;
    try {
 
      shellProcess = Runtime.getRuntime().exec(shPath);
      shellErrorResultReader = new BufferedReader(new InputStreamReader(shellProcess.getErrorStream()));
      shellInfoResultReader =  new BufferedReader(new InputStreamReader(shellProcess.getInputStream()));
      String infoLine;
      while ((infoLine = shellInfoResultReader.readLine()) != null) {
        logger.info("腳本文件執(zhí)行信息:{}", infoLine);
      }
      String errorLine;
      while ((errorLine = shellErrorResultReader.readLine()) != null) {
        logger.warn("腳本文件執(zhí)行信息:{}", errorLine);
      }
      // 等待程序執(zhí)行結(jié)束并輸出狀態(tài)
      exitCode = shellProcess.waitFor();
      if (0 == exitCode) {
        logger.info("腳本文件執(zhí)行成功:" + exitCode);
      } else {
        logger.error("腳本文件執(zhí)行失敗:" + exitCode);
      }
    } catch (Exception e) {
      logger.error("shell腳本執(zhí)行錯誤", e);
    } finally {
      if (null != shellInfoResultReader) {
        try {
          shellInfoResultReader.close();
        } catch (IOException e) {
          logger.error("流文件關(guān)閉異常:", e);
        }
      }
      if (null != shellErrorResultReader) {
        try {
          shellErrorResultReader.close();
        } catch (IOException e) {
          logger.error("流文件關(guān)閉異常:", e);
        }
      }
      if (null != shellProcess) {
        shellProcess.destroy();
      }
}

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java生成驗證碼

    Java生成驗證碼

    本文介紹了Java生成驗證碼的流程與方法。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • java解一個比較特殊的數(shù)組合并題

    java解一個比較特殊的數(shù)組合并題

    這篇文章主要介紹了java解一個比較特殊的數(shù)組合并題,需要的朋友可以參考下
    2014-06-06
  • 10個Java文件操作必備技巧分享

    10個Java文件操作必備技巧分享

    在我們?nèi)粘5拈_發(fā)中,文件操作是一個非常重要的主題。文件讀寫、文件復制、任意位置讀寫、緩存等技巧都是我們必須要掌握的。本文為大家整理了10個實用的文件操作技巧,希望對大家有所幫助
    2023-04-04
  • Redis分布式鎖實現(xiàn)方式及超時問題解決

    Redis分布式鎖實現(xiàn)方式及超時問題解決

    這篇文章主要介紹了Redis分布式鎖實現(xiàn)方式及超時問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • Java詳細講解包的作用以及修飾符的介紹

    Java詳細講解包的作用以及修飾符的介紹

    本文主要講述的是包的使用和注意事項和四種訪問修飾符public,protected,默認的,private的訪問范圍及實例,感興趣的朋友一起來看看
    2022-05-05
  • Mybatis使用foreach批量更新數(shù)據(jù)報無效字符錯誤問題

    Mybatis使用foreach批量更新數(shù)據(jù)報無效字符錯誤問題

    這篇文章主要介紹了Mybatis使用foreach批量更新數(shù)據(jù)報無效字符錯誤問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java多線程并發(fā)編程 Synchronized關(guān)鍵字

    Java多線程并發(fā)編程 Synchronized關(guān)鍵字

    現(xiàn)有一成員變量 Test,當線程 A 調(diào)用 Test 的 synchronized 方法,線程 A 獲得 Test 的同步鎖,同時,線程 B 也去調(diào)用 Test 的 synchronized 方法,此時線程 B 無法獲得 Test 的同步鎖,必須等待線程 A 釋放 Test 的同步鎖才能獲得從而執(zhí)行對應方法的代碼
    2017-05-05
  • java+SpringBoot設(shè)計實現(xiàn)評教系統(tǒng)

    java+SpringBoot設(shè)計實現(xiàn)評教系統(tǒng)

    這篇文章主要介紹了用過Java SpringBoot實現(xiàn)一個簡單的評價系統(tǒng),可以做到學生管理、教師管理、評教管理、指標管理、課程管理等。感興趣的可以了解一下
    2021-12-12
  • 使用Filter攔截器如何實現(xiàn)請求跨域轉(zhuǎn)發(fā)

    使用Filter攔截器如何實現(xiàn)請求跨域轉(zhuǎn)發(fā)

    這篇文章主要介紹了使用Filter攔截器如何實現(xiàn)請求跨域轉(zhuǎn)發(fā),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 詳解Java的位運算

    詳解Java的位運算

    這篇文章主要介紹了詳解Java的位運算,程序中的所有數(shù)在計算機內(nèi)存中都是以二進制的形式儲存的。位運算就是直接對整數(shù)在內(nèi)存中的二進制位進行操作,需要的朋友可以參考下
    2023-04-04

最新評論

涡阳县| 胶州市| 中西区| 澄迈县| 洪洞县| 嵊州市| 太湖县| 枞阳县| 津南区| 庄浪县| 萨嘎县| 潜山县| 凉城县| 山西省| 漯河市| 辽阳县| 固原市| 比如县| 始兴县| 鹿邑县| 屯留县| 库尔勒市| 黔南| 深圳市| 桦甸市| 广州市| 收藏| 兴宁市| 翼城县| 安化县| 维西| 钟祥市| 青铜峡市| 婺源县| 乌拉特后旗| 棋牌| 抚州市| 五家渠市| 仪征市| 若羌县| 高青县|