在Java中多次运行命令行程序 - 这是正确的吗?

时间:2010-11-12 16:39:06

标签: java multithreading runtime

我有一个程序(在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();
}

这非常有效,并且实际上设法将我的计划表现提高了十倍。所以,我的问题是:这是正确的吗?或者我错过了一些关于以这种方式做事的事情,最终会使一切变得非常错误?

2 个答案:

答案 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