Java ProcessBuilder Limitations

I have a Java program that connects to a local server via sockets, and I would not want to start the server manually if Java detects that it is not running. Therefore, if Java is not connected to the server, I use ProcessBuilder to start it:

new ProcessBuilder(new String[]{"/bin/bash", "-c", "./start_server"}).start();

Which starts the server and starts about 4 minutes until the server process responds. Interestingly, if I send more commands, it takes less time. I am wondering if I can limit the ProcessBuilder limit, possibly using too much memory. I am printing a message to the server on the server side, as this is being called from ProcessBuilder. I assume that it is directed elsewhere, and that is the problem.

+1
source share
1 answer

You need to read the result (even if you just throw it away), both stdout and stderr. Otherwise, the output buffer will fill up, resulting in odd behavior.

The simplest approach would be to redirect to bit-bit (assuming Java 1.7 +):

File bitbucket;

if (isWindows()) {
    bitbucket = new File("NUL");
} else {
    bitbucket = new File("/dev/null");
}

Process process = new ProcessBuilder("/bin/bash", "-c", "./start_server")
                  .redirectOutput(ProcessBuilder.Redirect.appendTo(bitbucket))
                  .redirectError(ProcessBuilder.Redirect.appendTo(bitbucket))
                  .start();

But if you need to use Java 1.6 or lower, you will have to minimize it yourself. This is what I use in my projects:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class StreamConsumer
{
    private final InputStream stream;

    private StreamConsumer(InputStream is)
    {
        this.stream = is;
    }

    private Runnable worker()
    {
        return new Worker();
    }

    private class Worker implements Runnable
    {
        @Override
        public void run()
        {
            try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
                while (br.readLine() != null) {
                    /* No one cares */
                }
            } catch (IOException ioe) {
                /* No one cares */
            }
        }
    }

    public static void consume(InputStream stream, String label)
    {
        Thread t = new Thread(new StreamConsumer(stream).worker(), label);
        t.setPriority(Thread.MIN_PRIORITY);
        t.start();
    }
}

And you would call it that:

Process process = new ProcessBuilder("/bin/bash", "-c", "./start_server")
                      .start();

StreamConsumer.consume(process.getInputStream(), "STDOUT");
StreamConsumer.consume(process.getErrorStream(), "STDERR");

Or like this:

Process process = new ProcessBuilder("/bin/bash", "-c", "./start_server")
                      .redirectErrorStream(true)
                      .start();

StreamConsumer.consume(process.getInputStream(), "STDOUT/STDERR");

Note that the constructor ProcessBuilderaccepts String...(varargs), not String[](although you can create and pass String[]manually if you want)

+2
source

Source: https://habr.com/ru/post/1619327/


All Articles