解決Java執(zhí)行Cmd命令出現(xiàn)的死鎖問題
問題
之前研究了Java通過執(zhí)行cmd命令從而觸發(fā)Android打包的思路,但是發(fā)現(xiàn)Android打包成功之后,后面的代碼邏輯就不走了(連輸出都沒有)
經過了一天的排查,終于是從網(wǎng)上找到了解決方法
原因及解決方法
原因分析: 在上面提及了, process創(chuàng)建的子進程沒有自己的控制臺或終端,其所有的io操作都是通過(輸入流、輸出流、錯誤流)重定向到父進程中
如果該可執(zhí)行程序的輸入、輸出或者錯誤輸出比較多的話,而由于運行窗口的標準輸入、輸出等緩沖區(qū)有大小的限制,則可能導致子進程阻塞,甚至產生死鎖
其解決方法就是在waitfor()方法之前讀出窗口的標準輸出、輸出、錯誤緩沖區(qū)中的內容。
方法封裝
下面代碼中的TeeInputStream是在lang3包依賴中,記得添加依賴
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>
Java版本:
/**
* 執(zhí)行命令行,并等待命令執(zhí)行完畢,同時將過程中的控制臺輸出日志寫入日志文件中
* @param cmd 命令,window記得要使用cmd /c開頭,如cmd /c ipconfig
* @param dir 命令行所在路徑
* @param logFile 日志文件
* @throws IOException
* @throws InterruptedException
*/
private void execCmdLine(String cmd, File dir, File logFile) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec(cmd, null, dir);
InputStream inputStream = process.getInputStream();
//開啟兩個線程用來讀取流,否則會造成死鎖問題
new Thread(() -> {
FileOutputStream fileOutputStream = null;
TeeInputStream teeInputStream = null;
BufferedReader bufferedReader = null;
try {
fileOutputStream = new FileOutputStream(logFile, true);
//使用分流器,輸出日志文件
teeInputStream = new TeeInputStream(inputStream, fileOutputStream);
//這里gbk格式需要注意,我是在window上測試的,所以使用是gbk方式,如果是其他平臺,可能需要使用utf-8格式
bufferedReader = new BufferedReader(new InputStreamReader(teeInputStream, "gbk"));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedReader.close();
teeInputStream.close();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
InputStreamReader err = new InputStreamReader(process.getErrorStream());
BufferedReader bferr = new BufferedReader(err);
String errline = "";
try {
while ((errline = bferr.readLine()) != null) {
System.out.println("流錯誤:" + errline);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bferr.close();
err.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
process.waitFor();
process.destroy();
}Kotlin版本:
/**
* 執(zhí)行命令行,并等待命令執(zhí)行完畢,同時將過程中的控制臺輸出日志寫入日志文件中
* - [cmd] 命令,window記得要使用cmd /c開頭,如cmd /c ipconfig
* - [dir] 命令行所在路徑
* - [logFile] 日志文件
*/
fun execCmd(cmd: String, dir: File, logFile: File) {
val process = Runtime.getRuntime().exec(cmd, null, dir)
val inputStream = process.inputStream
//開啟兩個線程用來讀取流,否則會造成死鎖問題
thread {
var fileOutputStream: FileOutputStream? = null
var teeInputStream: TeeInputStream? = null
var bufferedReader: BufferedReader? = null
try {
fileOutputStream = FileOutputStream(logFile, true)
//使用分流器,日志文件和
teeInputStream = TeeInputStream(inputStream, fileOutputStream)
//區(qū)分不同平臺
bufferedReader = if (isWin()) {
BufferedReader(InputStreamReader(teeInputStream, "gbk"))
} else {
BufferedReader(InputStreamReader(teeInputStream, "utf-8"))
}
var line: String?
while (bufferedReader.readLine().also { line = it } != null) {
println(line)
}
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
bufferedReader!!.close()
teeInputStream!!.close()
fileOutputStream!!.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
thread {
val err = InputStreamReader(process.errorStream)
val bferr = BufferedReader(err)
var errline = ""
try {
while (bferr.readLine().also { errline = it } != null) {
println("流錯誤:$errline")
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
try {
bferr.close()
err.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
process.waitFor()
process.destroy()
}代碼封裝在庫中stars-one/common-controls: TornadoFx的常用控件 controls for tornadofx
參考
到此這篇關于關于Java執(zhí)行Cmd命令出現(xiàn)的死鎖問題解決的文章就介紹到這了,更多相關Java執(zhí)行Cmd命令死鎖內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
基于springboot+vue實現(xiàn)垃圾分類管理系統(tǒng)
這篇文章主要為大家詳細介紹了基于springboot+vue實現(xiàn)垃圾分類管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-07-07
mybatis-plus 如何判斷參數(shù)是否為空并作為查詢條件
這篇文章主要介紹了mybatis-plus 如何判斷參數(shù)是否為空并作為查詢條件,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringBoot整合Swagger3生成接口文檔過程解析
這篇文章主要介紹了SpringBoot整合Swagger3生成接口文檔過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-07-07
IDEA設置生成帶注釋的getter和setter的圖文教程
通常我們用idea默認生成的getter和setter方法是不帶注釋的,當然,我們同樣可以設置idea像MyEclipse一樣生成帶有Javadoc的模板,具體設置方法,大家參考下本文2018-05-05
在SpringBoot 中從application.yml中獲取自定義常量方式
這篇文章主要介紹了在SpringBoot 中從application.yml中獲取自定義常量方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
intellij idea修改maven配置時總是恢復默認配置的解決方法idea版本(2020.2.x)
這篇文章主要介紹了intellij idea修改maven配置時總是恢復默認配置的解決方法idea版本(2020.2.x),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08
springboot整合mybatis實現(xiàn)簡單的一對多級聯(lián)查詢功能
這篇文章主要介紹了springboot整合mybatis實現(xiàn)簡單的一對多級聯(lián)查詢功能,分步驟通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-08-08

