Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a thread to capture process output

I am using a thread to capture stream output from a process, and then outputting that stream to the eclipse console. The question I have is when to terminate the thread that is doing the stream output.

Thread t = new Thread(new Runnable(){
        private boolean isProcessDone(Process p)
        {
            //not sure what to do here
        }
        public void run()
        {
            Process p = Runtime.getRuntime().exec("executable with output");
            BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
            BufferedReader error = new BufferedReader (new InputStreamReader(p.getErrorStream()));
            while ( !isProcessDone(p) ) {
                String line;
                if( (line = input.readLine()) != null )
                {
                    System.out.println(line);
                }
                if( (line = error.readLine()) != null )
                {
                    System.out.println(line);
                }
            }
            input.close();  
            error.close();      
        }
    });
    t.start();

My question is what belongs in the isProcessDone() function. The example I am basing this off of uses the stream's ready() function, but I am unclear whether this will work for programs that either std::err and std::out, but not both. I also tried using

try{
    p.exitValue();
    return true;
}catch(IllegalThreadStateException e){}
return false;

but then the thread finishes before the while loop has a chance to act on the streams, and the output is lost.

like image 440
Adrian Park Avatar asked Dec 31 '25 18:12

Adrian Park


2 Answers

You need to use Process.waitFor() to wait for process completion.

Additionally, you need to consume stdout and stderr concurrently in order to avoid blocking and a possible process hang. Consequently you need two threads to read these streams, and to continue reading whilst the streams are available.

See this Javaworld article for more info and a StreamGobbler implementation to consume the stdout/err.

like image 164
Brian Agnew Avatar answered Jan 03 '26 10:01

Brian Agnew


You can use VerboseProcess from jcabi-log (I'm a developer):

String name = new VerboseProcess(
  new ProcessBuilder("executable with output")
).stdout();

The only dependency you need:

<dependency>
  <groupId>com.jcabi</groupId>
  <artifactId>jcabi-log</artifactId>
  <version>0.7.5</version>
</dependency>
like image 22
yegor256 Avatar answered Jan 03 '26 10:01

yegor256



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!