我有一个程序(在Java中)需要在执行期间多次使用另一个程序,使用不同的参数。它是多线程的,除了在程序执行期间调用该程序之外还需要做其他事情,所以我需要使用Java来做到这一点。
问题是,所有Runtime.exec()
调用似乎都是由Java以同步的方式完成的,这样线程就不会在函数本身,而是在Java调用中遇到瓶颈。因此,我们有一个非常慢的运行程序,但这不会成为任何系统资源的瓶颈。
为了解决这个问题,我决定不关闭Process,并使用这个脚本进行所有调用:
#!/bin/bash
read choice
while [ "$choice" != "end" ]
do
$choice
read choice
done
所有以前的exec调用都被替换为:
private Process ntpProc;
Initializer(){
try {
ntpProc = Runtime.getRuntime().exec("./runscript.sh");
} catch (Exception ex) {
//Error Processing
}
}
public String callFunction(String function) throws Exception e{
OutputStream os = ntpProc.getOutputStream();
String result = "";
os.write((function + "\n").getBytes());
os.flush();
BufferedReader bis = new BufferedReader(new InputStreamReader(ntpProc.getInputStream()));
int timeout = 5;
while(!bis.ready() && timeout > 0){
try{
sleep(1000);
timeout--;
}
catch (InterruptedException e) {}
}
if(bis.ready()){
while(bis.ready()) result += bis.readLine() + "\n";
String errorStream = "";
BufferedReader bes = new BufferedReader(new InputStreamReader(ntpProc.getErrorStream()));
while(bes.ready()) errorStream += bes.readLine() + "\n";
}
return result;
}
public void Destroyer() throws exception{
BufferedOutputStream os = (BufferedOutputStream) ntpProc.getOutputStream();
os.write(("end\n").getBytes());
os.close();
ntpProc.destroy();
}
这非常有效,并且实际上设法将我的计划表现提高了十倍。所以,我的问题是:这是正确的吗?或者我错过了一些关于以这种方式做事的事情,最终会使一切变得非常错误?
答案 0 :(得分:3)
如果你想从进程错误和输入流(也就是stderr和stdout)中读取,你需要在专用线程上完成这项工作。
主要问题是你需要在缓冲区填满时清空它们,而你只能在一个单独的线程上执行此操作。
你做了什么,你已经设法缩短了输出,所以它不会溢出这些缓冲区,但潜在的问题仍然存在。
另外,根据过去的经验,从Java调用外部进程非常慢,所以你的方法可能会更好。
答案 1 :(得分:1)
只要不调用Proccess.waitFor(),进程的执行就不会阻塞。正如亚历克斯所说 - 在你的情况下阻塞由这些循环读取输出。
您可以使用commons-exec包,因为它提供了运行进程(同步或异步),处理输出,设置超时等的好方法。
以下是项目的链接: http://commons.apache.org/exec/
使用api的最好例子是他们拥有的测试类: http://svn.apache.org/viewvc/commons/proper/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java?view=markup