Sarp Kaya
Sarp Kaya

Reputation: 3784

Java run async processes

I am trying to run an async process and I do not want the program to wait until the end of these processes executions. I found this question how to run shell script asynchronously from within Java program but it doesn't have the answer that I am looking for.

What I am doing is I am simply running bash processes and after I run it, I do not want the Java program to wait until it's finished. This is what I have done:

public void runCommandLine(String directory) throws IOException {
    Thread commandLineThread = new Thread(() -> {
        try {
            ProcessBuilder processBuilder = new ProcessBuilder(
                    "/bin/bash");
            processBuilder.directory(new File(directory));
            Process process = processBuilder.start();
            try (OutputStreamWriter osw = new OutputStreamWriter(process.getOutputStream())) {
                osw.write(command);
            }
            printStream(process.getErrorStream(), true);
            printStream(process.getInputStream(), true);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    });
    commandLineThread.start();
    System.out.println("Task Dispatched");
}

I also put another print out at the end of the main method so I get this output:

Task Dispatched
Task Dispatched
End of psvm

However the program does not terminate as these two processes have not terminated.

How can I solve this issue?

Upvotes: 8

Views: 11696

Answers (3)

Vijay Kumar
Vijay Kumar

Reputation: 2707

           Thread commandLineThread = new Thread(() -> {
            try {
                BufferedReader br=new BufferedReader(
                        new InputStreamReader(
                                process.getInputStream()));
                String line;

                while((line=br.readLine())!=null){
                    System.out.println(line);
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        });
        commandLineThread.setDaemon(true);
        commandLineThread.start();

Upvotes: 0

K Erlandsson
K Erlandsson

Reputation: 13696

You need to make your thread a daemon thread. Use setDaemon(true) before starting it.

 commandLineThread.setDaemon(true);

A daemon thread is a thread that does not prevent the JVM from exiting. See this question: What is Daemon thread in Java? for more information about daemon threads.

Edit:

By judging from your comments you need the command to run even though the JVM is about to exit. I assume the command variable contains the script you want to run? You could make two changes to make the program behave as I think you want.

  1. Start bash with -c to execute your command, then you do not have to send things to an output stream.
  2. Start the process before starting your thread that waits for the output.

The resulting code would look something like:

public void runCommandLine(String directory) throws IOException {
    ProcessBuilder processBuilder = new ProcessBuilder(
                    "/bin/bash -c " + command);
    processBuilder.directory(new File(directory));
    Process process = processBuilder.start();
    Thread commandLineThread = new Thread(() -> {
        try {
            printStream(process.getErrorStream(), true);
            printStream(process.getInputStream(), true);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    });
    commandLineThread.setDaemon(true);
    commandLineThread.start();
    System.out.println("Task Dispatched");
}

Upvotes: 5

Juned Ahsan
Juned Ahsan

Reputation: 68715

You are reading the output streams of your process, and thats the reason your java program does not exit:

        printStream(process.getErrorStream(), true);
        printStream(process.getInputStream(), true);

Your stream reading will keep blocking your code.

You may like to redirect output of your launched process to a log file and read that later.

Upvotes: 0

Related Questions