原文:关于Java执行Cmd命令出现的死锁问题解决 - Stars-One的杂货小窝

问题

之前研究了Java通过执行cmd命令从而触发Android打包的思路,但是发现Android打包成功之后,后面的代码逻辑就不走了(连输出都没有)

经过了一天的排查,终于是从网上找到了解决方法

原因及解决方法

原因分析: 在上面提及了, process创建的子进程没有自己的控制台或终端,其所有的io操作都是通过(输入流、输出流、错误流)重定向到父进程中

如果该可执行程序的输入、输出或者错误输出比较多的话,而由于运行窗口的标准输入、输出等缓冲区有大小的限制,则可能导致子进程阻塞,甚至产生死锁

其解决方法就是在waitfor()方法之前读出窗口的标准输出、输出、错误缓冲区中的内容。

方法封装

下面代码中的TeeInputStream是在lang3包依赖中,记得添加依赖

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>

Java版本:

/**
* 执行命令行,并等待命令执行完毕,同时将过程中的控制台输出日志写入日志文件中
* @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版本:

/**
* 执行命令行,并等待命令执行完毕,同时将过程中的控制台输出日志写入日志文件中
* - [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)
//区分不同平台
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执行Cmd命令出现的死锁问题解决的更多相关文章

  1. java执行cmd命令并获取输出结果

    1.java执行cmd命令并获取输出结果 import java.io.BufferedReader; import java.io.InputStreamReader; import org.apa ...

  2. 如何使用Java执行cmd命令

    用JAVA代码实现执行CMD命令的方法! Runtime rt = Runtime.getRuntime(); Process p = rt.exec(String[] cmdarray);     ...

  3. Java执行cmd命令、bat脚本、linux命令,shell脚本等

    1.Windows下执行cmd命令 如复制 D:\tmp\my.txt 到D:\tmp\my_by_only_cmd.txt 现文件如图示: 执行代码: private static void run ...

  4. 解决方案--java执行cmd命令ProcessBuilder--出错Exception in thread "main" java.io.IOException: Cannot run program "dir d:\": CreateProcess error=2(xjl456852原创)

    当我尝试在java中通过ProcessBuilder运行window的cmd命令时出现错误: public static void main(String [] args) throws IOExce ...

  5. java执行cmd命令和linux命令

    文章出处http://blog.csdn.net/xh16319/article/details/17302947 一:window下执行cmd指定 一:window下执行cmd指定 程序例子: [j ...

  6. JAVA执行cmd命令方法

    package com.cmd; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStre ...

  7. Java执行CMD命令

    参见:https://blog.csdn.net/lixingshi/article/details/50467840 public static void runtimeCommand() thro ...

  8. Java执行cmd命令工具类

    工具类: public class CmdTask implements Runnable { private String command; private String dirPath; publ ...

  9. java中执行cmd命令

    一.java执行cmd命令的三种方式:http://www.jb51.net/article/80829.htm 参考:https://www.cnblogs.com/zhufu9426/p/7928 ...

  10. Java 调用并执行cmd命令

    cmd java 调用 执行 概要: Java 调用并执行cmd命令 Java | 复制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 2 ...

随机推荐

  1. Data Encryption Standard算法:历经考验的经典加密方案

    在当今数字化时代,数据安全是一个至关重要的问题.为了保护敏感数据的机密性和完整性,加密算法成为了数据保护的关键技术.其中,DES(Data Encryption Standard)算法作为一种经典的对 ...

  2. .NET Core开发实战(第6课:作用域与对象释放行为)--学习笔记(下)

    06 | 作用域与对象释放行为 接下来,把服务切换为单例模式,通过工厂的方式 services.AddSingleton<IOrderService>(p => new Dispos ...

  3. JS模块化系统

    随着 JavaScript 开发变得越来越广泛,命名空间和依赖关系变得越来越难以处理.人们已经开发出不同的解决方案以模块系统的形式来解决这个问题. CommonJS(CJS) CommonJS 是一种 ...

  4. NC20909 游戏

    题目链接 题目 题目描述 有 n 个人围成一个环玩传球游戏,每轮游戏手里拿着球的那个人必须将球传给他(她)的一个朋友.游戏一共进行了 m 轮,初始球在第 a 个人手中,问游戏结束后球在第 b 个人手中 ...

  5. NAND flash 扫盲博客

    从SSD角度学习NAND Flash(一)_小小单片机的博客-CSDN博客 从SSD角度学习NAND Flash(二)_ssd和nand 的交互_小小单片机的博客-CSDN博客 从SSD角度学习NAN ...

  6. C语言中,指针变量的坑

    先看一个初始化带头结点单链表的例子,LNode是结点变量,LinkList是结点指针变量,等同于LNode* typedef struct LNode{ // 定义单链表节点类型 int data; ...

  7. Ubuntu20.04/22.04 ESP32 命令行开发环境配置

    ESP32 芯片系列 ESP32分三个系列 ESP32-S ESP32-S3: Xtensa 32位 LX7 双核 240 MHz, 384KB ROM, 512KB SRAM, QFN7x7, 56 ...

  8. RFID EPC Class1 Gen2电子标签笔记

    RFID EPC Class1 Gen2 符合EPC Class1 Gen2(简称G2)协议V109版的电子标签(Tag)和读写器(Reader)应该具有下述的特性 标签存储器分区 Tag memor ...

  9. ORACLE查询优化及gather_plan_statistics hint

    查询优化手段和gather_plan_statistics hint: 在10g以后我们可以通过利用gather_plan_statistics提示来了解更多的SQL执行统计信息,具体使用方法如下: ...

  10. 项目实战:C#上位机+arduino下位机+控制点亮LED灯

    前言   当前比较流行的arduino开发,联动做一个Demo.   应用构架   上位机:C#上位机通过串口发送接收控制协议,来控制下位机:  下位机:arduino下位机主控,接受上位机串口协议控 ...