Java提供两种方法启动其他应用程序:
1) final Process process = Runtime.getRuntime().exec(cmd);
2) ProcessBuilder processBuilder = new ProcessBuilder(cmd); processBuilder.start();
问题描述:从DB获取900条数据,每条数据生成一个文件,当文件生成完成之后,调用系统命令zip对所有文件进行打包处理,发现命令调用后子线程阻塞无法返回。
分析JVM调用三方进程原理得知:JVM在启动子进程时,会和该进程建立三个管道,用于处理标准输入流,标准输出流,标准错误流。程序在执行过程中,会不断的向JVM写入标准输出和标准错误输出,JVM对此提供的缓存池有大小限制,当标准输出或者标准错误输出写满缓存池时,程序无法继续写入,因此子进程无法正常退出,导致线程阻塞。
解决方案:
1):新开线程读取标准输出及标准错误输出:
final Process process = Runtime.getRuntime().exec(cmd);
final InputStream errOutPut = process.getErrorStream();
final InputStream stdOutPut = process.getInputStream();
new Thread(){
@Override
public void run() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(errOutPut));
String content;
StringBuffer buffer = new StringBuffer();
while ((content = reader.readLine()) != null) {
buffer.append(content + "\n");
}
Log.d(buffer.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
errOutPut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread(){
@Override
public void run() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(stdOutPut));
String content;
StringBuffer buffer = new StringBuffer();
while ((content = reader.readLine()) != null) {
buffer.append(content + "\n");
}
Log.d(buffer.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
stdOutPut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
System.out.println("wait process exit...");
if (0 != process.waitFor()) {
System.out.println("exit fail: " + process.exitValue());
return false;
}
System.out.println("exit normal.");
2):使用ProcessBuilder将标准输出或者标准错误输出重定向。
3):尝试调用时通过设置不对标准输出或者标准错误输出处理(未验证)。