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ū),這樣問題就得到解決了。
所以我們在遇到java調(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)文章
java開發(fā)中如何使用JVisualVM進行性能分析
JVisualVM是由Sun提供的性能分析工具,如此強大的后盾怎能不強大?在Jdk6.0以后的版本中是自帶的,配置好環(huán)境變量然后在運行中輸入“JVisualVm”或直接到Jdk的安裝目錄的Bin目錄下找到運行程序即可運行。如果是用Jdk1.5或以前版本的朋友就得要單獨安裝了2015-12-12
springboot如何使用yml文件方式配置shardingsphere
這篇文章主要介紹了springboot如何使用yml文件方式配置shardingsphere問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09
學習不同 Java.net 語言中類似的函數(shù)結(jié)構(gòu)
這篇文章主要介紹了學習不同 Java.net 語言中類似的函數(shù)結(jié)構(gòu),函數(shù)式編程語言包含多個系列的常見函數(shù)。但開發(fā)人員有時很難在語言之間進行切換,因為熟悉的函數(shù)具有不熟悉的名稱。函數(shù)式語言傾向于基于函數(shù)范例來命名這些常見函數(shù)。,需要的朋友可以參考下2019-06-06
基于RecyclerChart的KLine繪制Volume實現(xiàn)詳解
這篇文章主要為大家介紹了基于RecyclerChart的KLine繪制Volume實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03
JavaEE開發(fā)基于Eclipse的環(huán)境搭建以及Maven Web App的創(chuàng)建
本文主要介紹了如何在Eclipse中創(chuàng)建的Maven Project,本文是JavaEE開發(fā)的開篇,也是基礎。下面內(nèi)容主要包括了JDK1.8的安裝、JavaEE版本的Eclipse的安裝、Maven的安裝、Tomcat 9.0的配置、Eclipse上的M2Eclipse插件以及STS插件的安裝。2017-03-03
Java旋轉(zhuǎn)數(shù)組中最小數(shù)字具體實現(xiàn)(圖文詳解版)
這篇文章主要給大家介紹了關(guān)于Java旋轉(zhuǎn)數(shù)組中最小數(shù)字具體實現(xiàn)的相關(guān)資料,旋轉(zhuǎn)數(shù)組,說明數(shù)據(jù)不變,只是改變位置,文中通過代碼示例介紹的非常詳細,需要的朋友可以參考下2023-08-08
springboot+mybatis-plus 兩種方式打印sql語句的方法
這篇文章主要介紹了springboot+mybatis-plus 兩種方式打印sql語句的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-10-10

