Java Process與Runtime()的使用及調(diào)用cmd命令阻塞的解決方案
Java Process與Runtime()使用
java調(diào)用cmd執(zhí)行bat文件有時會出現(xiàn)卡死的現(xiàn)象,當時感覺很迷惑,后來查資料,本來一般都是這樣來調(diào)用程序并獲取進程的輸出流的,但是我在windows上執(zhí)行這樣的調(diào)用的時候卻總是在while那里被堵塞了,結(jié)果造成ffmpeg程序在執(zhí)行了一會后不再執(zhí)行,這里從官方的參考文檔中我們可以看到這是由于緩沖區(qū)的問題,由于java進程沒有清空ffmpeg程序?qū)懙骄彌_區(qū)的內(nèi)容,結(jié)果導致ffmpeg程序一直在等待。
在網(wǎng)上也查找了很多這樣的問題,不過說的都是使用單獨的線程來進行控制,我也嘗試過很多網(wǎng)是所說的方法,可一直沒起什么作用。
一直認為是getInputStream的緩沖區(qū)沒有被清空,不過問題確實是緩沖區(qū)的內(nèi)容沒有被清空,但不是getInputStream的,而是getErrorStream的緩沖區(qū),這樣問題就得到解決了。
所以我們在遇到j(luò)ava調(diào)用外部程序而導致線程阻塞的時候,可以考慮使用兩個線程來同時清空process獲取的兩個輸入流,如下這段程序:
public String excuteBatFile(String file, boolean isCloseWindow)
{
String cmdCommand = null;
String res = null;
if(isCloseWindow)
{
cmdCommand = "cmd.exe /c " + file;
}else
{
cmdCommand = "cmd.exe /k " + file;
}
StringBuilder stringBuilder = new StringBuilder();
Process process = null;
try {
process = Runtime.getRuntime().exec(cmdCommand);
final InputStream is1 = process.getInputStream();
new Thread(new Runnable() {
public void run() {
BufferedReader bufferedReader = null;
String line = null;
try {
bufferedReader = new BufferedReader(
new InputStreamReader(is1, "GBK"));
while((line=bufferedReader.readLine()) != null)
{
stringBuilder.append(line+"\n");
}
is1.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start(); // 啟動單獨的線程來清空p.getInputStream()的緩沖區(qū)
InputStream is2 = process.getErrorStream();
BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));
StringBuilder buf = new StringBuilder(); // 保存輸出結(jié)果流
String line2 = null;
while((line2 = br2.readLine()) != null) buf.append(line2); //
log.info("----res:----" + stringBuilder + "&" + buf);
return stringBuilder + "&" + buf;
} catch (Exception e) {
e.printStackTrace();
return e.toString();
}
}
通過這樣我們使用一個線程來讀取process.getInputStream()的輸出流,使用另外一個線程來獲取process.getErrorStream()的輸出流,這樣我們就可以保證緩沖區(qū)得到及時的清空而不擔心線程被阻塞了。
當然根據(jù)需要你也可以保留process.getInputStream()流中的內(nèi)容,這個就看調(diào)用的程序的處理了。
java Process執(zhí)行cmd命令流阻塞處理
代碼如下:
public static void runCmd() {
Process process = null;
BufferedReader bufferedReader = null;
try {
Logger.getLogger(SystemService.class).info("============= 開始重啟機器 =============");
process = Runtime.getRuntime().exec("cmd.exe /c shutdown -r -f -t 0");
bufferedReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(process.getInputStream()), Charset.forName("GB2312")));
// 開啟線程讀取錯誤輸出,避免阻塞
new StreamInformatonThread(process.getErrorStream(), "error").start();
String outStr;
while ((outStr = bufferedReader.readLine()) != null) {
Logger.getLogger(SystemService.class).info("readLine -------> : " + outStr);
}
Logger.getLogger(SystemService.class).info("============= 重啟機器完成 =============");
} catch (IOException e) {
Logger.getLogger(SystemService.class).error("============= 重啟機器失敗 =============");
e.printStackTrace();
} finally {
if (process != null) {
process.destroy();
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
import java.io.*;
/**
* @Description:流阻塞處理
* @Author: zhangwenchao
* @Date: 2019/7/9 11:35
*/
public class StreamInformatonThread extends Thread {
private InputStream is;
private String str;
private Logger logger = Logger.getLogger(StreamInformatonThread.class);
public StreamInformatonThread(InputStream is, String str) {
this.is = is;
this.str = str;
}
public void run() {
BufferedReader out = null;
try {
out = new BufferedReader(new InputStreamReader(is, "gbk"));
String line;
while ((line = out.readLine()) != null) {
if (str.equals("error")) {
logger.info("ErrorStream --------> :" +line);
} else {
logger.info("outLine ---------> :" + line);
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
關(guān)于@CacheEvict無法解決分頁緩存清除的解決思路
這篇文章主要介紹了關(guān)于@CacheEvict無法解決分頁緩存清除的解決思路,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
SpringBoot自定義注解之實現(xiàn)AOP切面日志詳解
這篇文章主要為大家詳細介紹了SpringBoot自定義注解之實現(xiàn)AOP切面統(tǒng)一打印出入?yún)⑷罩?,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-09-09
SpringBoot自定義內(nèi)容協(xié)商的實現(xiàn)
Spring Cloud負載均衡及遠程調(diào)用實現(xiàn)詳解
java多線程編程之使用Synchronized關(guān)鍵字同步類方法
Java動態(tài)替換properties文件中鍵值方式

