3

I have a program (in Java) that needs to use another program multiple times, with different arguments, during it's execution. It is multi-threaded, and also needs to do other things besides calling that program during it's execution, so I need to use Java to do that.

The problem is, all Runtime.exec() calls seem to be done in a synchronized way by Java, such that threads get bottlenecked not around the functions themselves, but in the Java call. Thus, we have a very slow running program, but that does not bottleneck at any system resource.

In order to fix that problem, I decided to not close the Process, and make all calls using this script:

#!/bin/bash

read choice
while [ "$choice" != "end" ]
do
   $choice
   read choice
done

And all the previous exec calls are substituted by this:

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();
}

That works very well, and actually managed to improve my program performance tenfold. SO, my question is: Is this correct? Or am I missing somethings about doing things this way that will make everything go terribly wrong eventually?

1
  • Are you using the Java Threads correctly? I mean, are you calling start() or run()? Commented Nov 12, 2010 at 16:44

2 Answers 2

3

If you want to read from the process Error and Input streams ( aka stderr and stdout ), you need to do this job on dedicated threads.

The main problem is that you need to empty the buffers as they become filled up, and you can only do this on a separate thread.

What you did, you've managed to shorten the output, so it does not overflow these buffers, but the underlying problem is still there.

Also, from the past experience, calling external process from Java is extremely slow, so your approach may be better after all.

Sign up to request clarification or add additional context in comments.

Comments

1

As long as you not calling Proccess.waitFor(), execution of process will not block. As Alex said - blocking in your case caused by those loops to read the output.

You can use commons-exec package, as it provides a nice way of running processes (sync or async), handling output, setting timeouts, etc.

Here is a link to a project: http://commons.apache.org/exec/

The best example of using the api is test class they have: http://svn.apache.org/viewvc/commons/proper/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java?view=markup

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.