今天写程序遇到一个问题,使用Process process = Runtime.getRuntime().exec(cmd); proc.waitFor(); 创建一个进程后,如果进程产生大量的输出而不去读取的话,当超出系统的缓存时,此进程会被挂起,而正在运行的程序又因 proc.waitFor();在等待进程的消亡,所以产生了一个死锁。
从网上找到了一个解决方案:
碰到一个项目需要从Java中运行Perl程序,这个Perl程序调用客户的Web service,每次发送一个请求,接受一个响应。Java程序中包含多个请求,需要多次调用Perl程序,并且接受和解析响应(这个烂设计可不是我干 的,我实在不明白强大的Java Web Service为什么要弄成这样,不过客户是老大)。使用Java Runtime的exec()方法,发现运行一段时间后,进程就被挂起了(之前的响应完全正确)。于是分析原因,发现我在运行exec()方法后,立刻执 行了Process的waitFor()方法,这里出了问题。在网上找到一篇文章讲述这个问题:
地址:http://brian.pontarelli.com/2005/11/11/java-runtime-exec-can-hang/
November 11, 2005 on 4:40 pm | In Java |
The next version of Savant is going to focus heavily on the stand-alone runtime and support for dialects and plugins. Supporting all that is largely handled by using a simple executor framework I wrote around Java 1.4 and lower’s Runtime.exec method. A few things to keep in mind when using this:
可以看出:
于是将waitFor()方法放在读取数据流后调用,目前没有发现什么问题。
正好解决了我心中的疑问,非常感谢!
我们的程序一开始就是exec完了接着waitFor(),但bat文件执行不完整:
Process proc = Runtime.getRuntime().exec(cmd);
proc.waitFor();
后面的build中在waitFor()之前读取了数据流,bat文件就可以完整执行了:
Process proc = Runtime.getRuntime().exec(cmd);
StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "Error");
StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "Output");
errorGobbler.start();
outputGobbler.start();
proc.waitFor();
class StreamGobbler extends Thread {
InputStream is;
String type;
StreamGobbler(InputStream is, String type) {
this.is = is;
this.type = type;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
if (type.equals("Error"))
LogManager.logError(line);
else
LogManager.logDebug(line);
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
TestPrint.bat:
echo P1=%1 >D:/2.1.2env/2.1.2home/CompuSet/output/TestPrint.log
echo P2=%2 >>D:/2.1.2env/2.1.2home/CompuSet/output/TestPrint.log
echo P3=%3 >>D:/2.1.2env/2.1.2home/CompuSet/output/TestPrint.log
echo P4=%4 >>D:/2.1.2env/2.1.2home/CompuSet/output/TestPrint.log
echo P5=%5 >>D:/2.1.2env/2.1.2home/CompuSet/output/TestPrint.log
echo P6=%6 >>D:/2.1.2env/2.1.2home/CompuSet/output/TestPrint.log
Bad_TestPrint.log:
P1=C:/xPression/CompuSet/output/MartyTestOut1.afp
P2=Literal1
P3="Rick Skinner"
P4=Parameter3
Good_TestPrint.log
P1=C:/xPression/CompuSet/output/MartyTestOut1.afp
P2=Literal1
P3="Rick Skinner"
P4=Parameter3
P5=Parameter4
P6=Parameter5