Java Process與Runtime()的使用及調(diào)用cmd命令阻塞的解決方案
Java Process與Runtime()使用
java調(diào)用cmd執(zhí)行bat文件有時(shí)會(huì)出現(xiàn)卡死的現(xiàn)象,當(dāng)時(shí)感覺(jué)很迷惑,后來(lái)查資料,本來(lái)一般都是這樣來(lái)調(diào)用程序并獲取進(jìn)程的輸出流的,但是我在windows上執(zhí)行這樣的調(diào)用的時(shí)候卻總是在while那里被堵塞了,結(jié)果造成ffmpeg程序在執(zhí)行了一會(huì)后不再執(zhí)行,這里從官方的參考文檔中我們可以看到這是由于緩沖區(qū)的問(wèn)題,由于java進(jìn)程沒(méi)有清空f(shuō)fmpeg程序?qū)懙骄彌_區(qū)的內(nèi)容,結(jié)果導(dǎo)致ffmpeg程序一直在等待。
在網(wǎng)上也查找了很多這樣的問(wèn)題,不過(guò)說(shuō)的都是使用單獨(dú)的線(xiàn)程來(lái)進(jìn)行控制,我也嘗試過(guò)很多網(wǎng)是所說(shuō)的方法,可一直沒(méi)起什么作用。
一直認(rèn)為是getInputStream的緩沖區(qū)沒(méi)有被清空,不過(guò)問(wèn)題確實(shí)是緩沖區(qū)的內(nèi)容沒(méi)有被清空,但不是getInputStream的,而是getErrorStream的緩沖區(qū),這樣問(wèn)題就得到解決了。
所以我們?cè)谟龅絡(luò)ava調(diào)用外部程序而導(dǎo)致線(xiàn)程阻塞的時(shí)候,可以考慮使用兩個(gè)線(xiàn)程來(lái)同時(shí)清空process獲取的兩個(gè)輸入流,如下這段程序:
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(); // 啟動(dòng)單獨(dú)的線(xiàn)程來(lái)清空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(); } }
通過(guò)這樣我們使用一個(gè)線(xiàn)程來(lái)讀取process.getInputStream()的輸出流,使用另外一個(gè)線(xiàn)程來(lái)獲取process.getErrorStream()的輸出流,這樣我們就可以保證緩沖區(qū)得到及時(shí)的清空而不擔(dān)心線(xiàn)程被阻塞了。
當(dāng)然根據(jù)需要你也可以保留process.getInputStream()流中的內(nèi)容,這個(gè)就看調(diào)用的程序的處理了。
java Process執(zhí)行cmd命令流阻塞處理
代碼如下:
public static void runCmd() { Process process = null; BufferedReader bufferedReader = null; try { Logger.getLogger(SystemService.class).info("============= 開(kāi)始重啟機(jī)器 ============="); process = Runtime.getRuntime().exec("cmd.exe /c shutdown -r -f -t 0"); bufferedReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(process.getInputStream()), Charset.forName("GB2312"))); // 開(kāi)啟線(xiàn)程讀取錯(cuò)誤輸出,避免阻塞 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("============= 重啟機(jī)器完成 ============="); } catch (IOException e) { Logger.getLogger(SystemService.class).error("============= 重啟機(jī)器失敗 ============="); 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(); } } } } }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java開(kāi)發(fā)中如何使用JVisualVM進(jìn)行性能分析
JVisualVM是由Sun提供的性能分析工具,如此強(qiáng)大的后盾怎能不強(qiáng)大?在Jdk6.0以后的版本中是自帶的,配置好環(huán)境變量然后在運(yùn)行中輸入“JVisualVm”或直接到Jdk的安裝目錄的Bin目錄下找到運(yùn)行程序即可運(yùn)行。如果是用Jdk1.5或以前版本的朋友就得要單獨(dú)安裝了2015-12-12springboot如何使用yml文件方式配置shardingsphere
這篇文章主要介紹了springboot如何使用yml文件方式配置shardingsphere問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09學(xué)習(xí)不同 Java.net 語(yǔ)言中類(lèi)似的函數(shù)結(jié)構(gòu)
這篇文章主要介紹了學(xué)習(xí)不同 Java.net 語(yǔ)言中類(lèi)似的函數(shù)結(jié)構(gòu),函數(shù)式編程語(yǔ)言包含多個(gè)系列的常見(jiàn)函數(shù)。但開(kāi)發(fā)人員有時(shí)很難在語(yǔ)言之間進(jìn)行切換,因?yàn)槭煜さ暮瘮?shù)具有不熟悉的名稱(chēng)。函數(shù)式語(yǔ)言?xún)A向于基于函數(shù)范例來(lái)命名這些常見(jiàn)函數(shù)。,需要的朋友可以參考下2019-06-06基于RecyclerChart的KLine繪制Volume實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了基于RecyclerChart的KLine繪制Volume實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03JavaEE開(kāi)發(fā)基于Eclipse的環(huán)境搭建以及Maven Web App的創(chuàng)建
本文主要介紹了如何在Eclipse中創(chuàng)建的Maven Project,本文是JavaEE開(kāi)發(fā)的開(kāi)篇,也是基礎(chǔ)。下面內(nèi)容主要包括了JDK1.8的安裝、JavaEE版本的Eclipse的安裝、Maven的安裝、Tomcat 9.0的配置、Eclipse上的M2Eclipse插件以及STS插件的安裝。2017-03-03Java旋轉(zhuǎn)數(shù)組中最小數(shù)字具體實(shí)現(xiàn)(圖文詳解版)
這篇文章主要給大家介紹了關(guān)于Java旋轉(zhuǎn)數(shù)組中最小數(shù)字具體實(shí)現(xiàn)的相關(guān)資料,旋轉(zhuǎn)數(shù)組,說(shuō)明數(shù)據(jù)不變,只是改變位置,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-08-08springboot+mybatis-plus 兩種方式打印sql語(yǔ)句的方法
這篇文章主要介紹了springboot+mybatis-plus 兩種方式打印sql語(yǔ)句的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Java中定時(shí)器java.util.Timer的簡(jiǎn)單模擬
在Java中,定時(shí)器(Timer)是一個(gè)工具類(lèi),用于安排任務(wù)在指定時(shí)間后執(zhí)行或以指定的時(shí)間間隔重復(fù)執(zhí)行,本文就來(lái)講講如何簡(jiǎn)單模擬實(shí)現(xiàn)定時(shí)器吧2023-07-07Java集合的組內(nèi)平均值的計(jì)算方法總結(jié)
在Java中,經(jīng)常需要對(duì)集合進(jìn)行各種操作,其中之一就是計(jì)算集合的組內(nèi)平均值,本文將介紹如何使用Java集合來(lái)計(jì)算組內(nèi)平均值,并提供一些示例代碼和實(shí)用技巧2024-08-08Eolink上傳文件到Java后臺(tái)進(jìn)行處理的示例代碼
這篇文章主要介紹了Eolink上傳文件到Java后臺(tái)進(jìn)行處理,這里是上傳的excel表格數(shù)據(jù)并轉(zhuǎn)換為java集合對(duì)象、然后進(jìn)行業(yè)務(wù)邏輯處理判斷最后保存到數(shù)據(jù)庫(kù)?,需要的朋友可以參考下2022-12-12