java 使用Process調(diào)用exe程序 及 Process.waitFor() 死鎖問(wèn)題了解和解決

bgi.jpg

前言

最近在開發(fā)android的同時(shí)也在開發(fā)java ,碰到了需要使用java 程序調(diào)用exe的需求溪猿,這里我使用的 process 來(lái)調(diào)用的俭尖。該篇文章 讀完需要8+分鐘盆昙,文章類型為 小白入門類型,此處主要記錄嗜侮,方便以后學(xué)習(xí)補(bǔ)充... 如有不正確的地方還望海涵 及 指出....

文章參考
process參考

waitfor掛起解析

1. 使用process調(diào)用exe程序

ProcessBuilder pb = new ProcessBuilder("C:\\Debug\\TestRedis.exe", keyNmae);
pb.redirectErrorStream(true);
Process process = pb.start();
//可能導(dǎo)致進(jìn)程阻塞港令,甚至死鎖
int ret = process.waitFor();
System.out.println("return value:"+ret);
System.out.println(process.exitValue());
byte[] bytes = new byte[process.getInputStream().available()];
process.getInputStream().read(bytes);
System.out.println(new String(bytes));
// ProcessBuilder api 方法
public ProcessBuilder(String... command) {
        this.command = new ArrayList<>(command.length);
        for (String arg : command)
            this.command.add(arg);
    }

首先我們先使用 processBuilder 創(chuàng)建出該對(duì)象,該對(duì)象我這里暫時(shí)使用了第一個(gè)參數(shù)為 exe 文件的地址锈颗,第二個(gè)參數(shù)為傳遞參數(shù)顷霹,是我需要傳給exe 的字符串。后邊主要就是打印 輸入流击吱,獲取exe 輸出信息淋淀。其實(shí)到這里java 調(diào)用exe 就已經(jīng)完 了,但是后續(xù)開發(fā)中遇到一種問(wèn)題覆醇,就是程序莫名死鎖朵纷,沒(méi)有響應(yīng),于是使用debug 跟進(jìn)代碼永脓,發(fā)現(xiàn)程序走到 waitfor 代碼行的時(shí)候程序就出現(xiàn)了掛起的情況袍辞,于是google了一番,明白了其中的原因憨奸。

2. waitfor 問(wèn)題描述分析

1.主進(jìn)程中調(diào)用pb.start會(huì)創(chuàng)建一個(gè)子進(jìn)程革屠,用于執(zhí)行shell /exe 腳本。子進(jìn)程創(chuàng)建后會(huì)和主進(jìn)程分別獨(dú)立運(yùn)行。

  1. 因?yàn)橹鬟M(jìn)程需要等待腳本執(zhí)行完成似芝,然后對(duì)腳本返回值或輸出進(jìn)行處理那婉,所以這里主進(jìn)程調(diào)用Process.waitfor等待子進(jìn)程完成。
  2. 子進(jìn)程執(zhí)行過(guò)程就是不斷的打印信息党瓮。主進(jìn)程中可以通過(guò)Process.getInputStream和Process.getErrorStream獲取并處理详炬。
  3. 這時(shí)候子進(jìn)程不斷向主進(jìn)程發(fā)生數(shù)據(jù),而主進(jìn)程調(diào)用Process.waitfor后已掛起寞奸。當(dāng)前子進(jìn)程和主進(jìn)程之間的緩沖區(qū)塞滿后呛谜,子進(jìn)程不能繼續(xù)寫數(shù)據(jù),然后也會(huì)掛起枪萄。
  4. 這樣子進(jìn)程等待主進(jìn)程讀取數(shù)據(jù)隐岛,主進(jìn)程等待子進(jìn)程結(jié)束,兩個(gè)進(jìn)程相互等待瓷翻,最終導(dǎo)致死鎖聚凹。

3. 死鎖問(wèn)題解決

基于上述分析,只要主進(jìn)程在waitfor之前齐帚,能不斷處理緩沖區(qū)中的數(shù)據(jù)就可以妒牙。因?yàn)椋覀兛梢栽賥aitfor之前对妄,單獨(dú)啟兩個(gè)額外的線程湘今,分別用于處理InputStream和ErrorStream就可以

try {
            //獲取進(jìn)程的標(biāo)準(zhǔn)輸入流
            final InputStream is1 = process.getInputStream();
            //獲取進(jìn)城的錯(cuò)誤流
            final InputStream is2 = process.getErrorStream();
            //啟動(dòng)兩個(gè)線程,一個(gè)線程負(fù)責(zé)讀標(biāo)準(zhǔn)輸出流剪菱,另一個(gè)負(fù)責(zé)讀標(biāo)準(zhǔn)錯(cuò)誤流
            new Thread() {
                public void run() {
                    BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));
                    try {
                        String line1 = null;
                        while ((line1 = br1.readLine()) != null) {
                            if (line1 != null){}
                        }
                    } 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();

            //可能導(dǎo)致進(jìn)程阻塞摩瞎,甚至死鎖
            int ret = process.waitFor();
            System.out.println("return value:"+ret);
            System.out.println(process.exitValue());
            logger.info("event:{}", "RunExeForWindows",process.exitValue());
            byte[] bytes = new byte[process.getInputStream().available()];
            process.getInputStream().read(bytes);
            System.out.println(new String(bytes));
            logger.info("event:{}", "RunExeForWindows",new String(bytes));
        }catch (Exception ex){
            ex.printStackTrace();
            try{
                process.getErrorStream().close();
                process.getInputStream().close();
                process.getOutputStream().close();
            }
            catch(Exception ee){}
        }

如此便可以將 waitfor死鎖問(wèn)題避開,看完這個(gè)問(wèn)題琅豆,總結(jié)一下愉豺,多看官方api注釋....其實(shí)官方已經(jīng)提示我們,如下 為 api注釋

Causes the current thread to wait, if necessary, until the
     * process represented by this {@code Process} object has
     * terminated.  This method returns immediately if the subprocess
     * has already terminated.  If the subprocess has not yet
     * terminated, the calling thread will be blocked until the
     * subprocess exits.
@return the exit value of the subprocess represented by this
     *         {@code Process} object.  By convention, the value
     *         {@code 0} indicates normal termination.
     * @throws InterruptedException if the current thread is
     *         {@linkplain Thread#interrupt() interrupted} by another
     *         thread while it is waiting, then the wait is ended and
     *         an {@link InterruptedException} is thrown.

如果需要茫因,導(dǎo)致當(dāng)前線程等待蚪拦,直到此{(lán)@code Process}對(duì)象表示的進(jìn)程具有終止 如果子進(jìn)程,此方法立即返回已經(jīng)終止冻押。 如果子進(jìn)程還沒(méi)有終止后驰贷,調(diào)用線程將被阻塞,直到子進(jìn)程退出洛巢。

2018年7月3日 11:22:55

                                         -- 上海 大白
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末括袒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子稿茉,更是在濱河造成了極大的恐慌锹锰,老刑警劉巖芥炭,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異恃慧,居然都是意外死亡园蝠,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門痢士,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)彪薛,“玉大人,你說(shuō)我怎么就攤上這事怠蹂∩蒲樱” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵城侧,是天一觀的道長(zhǎng)易遣。 經(jīng)常有香客問(wèn)我,道長(zhǎng)赞庶,這世上最難降的妖魔是什么训挡? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮歧强,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘为肮。我一直安慰自己摊册,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布颊艳。 她就那樣靜靜地躺著茅特,像睡著了一般。 火紅的嫁衣襯著肌膚如雪棋枕。 梳的紋絲不亂的頭發(fā)上白修,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音重斑,去河邊找鬼兵睛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛窥浪,可吹牛的內(nèi)容都是我干的祖很。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼漾脂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼假颇!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起骨稿,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤笨鸡,失蹤者是張志新(化名)和其女友劉穎姜钳,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體形耗,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡傲须,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了趟脂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泰讽。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖昔期,靈堂內(nèi)的尸體忽然破棺而出已卸,到底是詐尸還是另有隱情,我是刑警寧澤硼一,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布累澡,位于F島的核電站,受9級(jí)特大地震影響般贼,放射性物質(zhì)發(fā)生泄漏愧哟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一哼蛆、第九天 我趴在偏房一處隱蔽的房頂上張望蕊梧。 院中可真熱鬧,春花似錦腮介、人聲如沸肥矢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)甘改。三九已至,卻和暖如春灭抑,著一層夾襖步出監(jiān)牢的瞬間十艾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工腾节, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留忘嫉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓禀倔,卻偏偏與公主長(zhǎng)得像榄融,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子救湖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354