关于Java执行Cmd命令出现的死锁问题解决
问题
之前研究了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命令出现的死锁问题解决的更多相关文章
- java执行cmd命令并获取输出结果
1.java执行cmd命令并获取输出结果 import java.io.BufferedReader; import java.io.InputStreamReader; import org.apa ...
- 如何使用Java执行cmd命令
用JAVA代码实现执行CMD命令的方法! Runtime rt = Runtime.getRuntime(); Process p = rt.exec(String[] cmdarray); ...
- Java执行cmd命令、bat脚本、linux命令,shell脚本等
1.Windows下执行cmd命令 如复制 D:\tmp\my.txt 到D:\tmp\my_by_only_cmd.txt 现文件如图示: 执行代码: private static void run ...
- 解决方案--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 ...
- java执行cmd命令和linux命令
文章出处http://blog.csdn.net/xh16319/article/details/17302947 一:window下执行cmd指定 一:window下执行cmd指定 程序例子: [j ...
- JAVA执行cmd命令方法
package com.cmd; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStre ...
- Java执行CMD命令
参见:https://blog.csdn.net/lixingshi/article/details/50467840 public static void runtimeCommand() thro ...
- Java执行cmd命令工具类
工具类: public class CmdTask implements Runnable { private String command; private String dirPath; publ ...
- java中执行cmd命令
一.java执行cmd命令的三种方式:http://www.jb51.net/article/80829.htm 参考:https://www.cnblogs.com/zhufu9426/p/7928 ...
- 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 ...
随机推荐
- Protobuf之proto基础语法
目录 1.说明 2.字段类型 3.字段规则 4.字段编号 5.注释 6.类型 6.1.message 6.2.service 7.枚举enum 8.保留字段 9.import 9.1.protoc指令 ...
- SDK多项目开发与联调
在SDK开发中,因为是往外提供的功能静态库,所以在开发的时候要验证开发的SDK是否功能正常,这里就需要做进行边开发边联调的工作. 下面使用的开发模式是创建一个WorkSpace工作工具,SDK项目和D ...
- STM8 bootloader 升级方案程序设计(一)
1.前言 上一篇单片机 IAP 功能基础开发篇之APP升级(一)讲到了单片机 IAP 功能给 APP 程序升级的设计思路,这篇介绍的是具体实现方式. 这篇介绍关于 STM8 系列实现 bootload ...
- 洛谷P1102 过河卒
P1102 过河卒 链接在此 过河卒 此题如果直接忽略掉马的影响的话,可以看出很简单的递推规律 即 \[dp[i][j]=dp[i-1][j]+dp[i][]j-1] \] 也就是说,由于卒只能走直线 ...
- AI热点概念解读:一文搞懂这些热词
自 ChatGPT 问世以来,AI的风口就来了. AI是一门研究如何使计算机具有类似人类智能的学科. 自从ChatGPT-3.5给大家带来了极大的震惊之后,全民都在谈论AI,在这个AI大时代背景之下, ...
- CentOS8-pacemaker+corosync高可用部署
部署pacemaker yum install pacemaker pcs corosync fence-agents resource-agents 启动pcs服务 systemctl enable ...
- rsyslog 系统日志收集上报(可增加自定义项目日志)
Linux 自带应用,没有复杂的依赖关系却有强大的日志采集上报功能 本文以上报阿里云为例 1.基础配置讲解 /etc/rsyslog.conf 为其主配置文件(不用动) /etc/rsyslog.d/ ...
- virtualapp安装应用流程源码分析
1. HomeActivity 为处理的入口 @Override protected void onActivityResult(int requestCode, int resultCode, In ...
- 一个有意思的问题:Kafka的消费Offset会溢出吗
最近在项目上接入公司APP产品的用户点击日志数据时,发现消费者组的Offset值非常大,才一天的时间,已提交的Offset值就有千亿级别了. 于是不禁想了一个问题:假设一个Topic就只有一个Part ...
- 新零售SaaS架构:订单履约系统的应用架构梳理
订单履约系统的核心能力 通过分析订单履约的全流程和各个业务活动,我们可以梳理出订单履约的核心业务链路,基于业务链路,我们抽象出订单履约系统的三大系统能力,分别为履约服务表达.履约调度.物流配送. 履约 ...