前言
最近在開發(fā)android的同時(shí)也在開發(fā)java ,碰到了需要使用java 程序調(diào)用exe的需求溪猿,這里我使用的 process 來(lái)調(diào)用的俭尖。該篇文章 讀完需要8+分鐘盆昙,文章類型為 小白入門類型,此處主要記錄嗜侮,方便以后學(xué)習(xí)補(bǔ)充... 如有不正確的地方還望海涵 及 指出....
文章參考
process參考
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)行。
- 因?yàn)橹鬟M(jìn)程需要等待腳本執(zhí)行完成似芝,然后對(duì)腳本返回值或輸出進(jìn)行處理那婉,所以這里主進(jìn)程調(diào)用Process.waitfor等待子進(jìn)程完成。
- 子進(jìn)程執(zhí)行過(guò)程就是不斷的打印信息党瓮。主進(jìn)程中可以通過(guò)Process.getInputStream和Process.getErrorStream獲取并處理详炬。
- 這時(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ì)掛起枪萄。
- 這樣子進(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
-- 上海 大白