[Java] [Implementation] Java Process class

3 minute read

version

java 8

API

First, let’s take a look at the Process class from Java API Docs.

Class Process java.lang.Object Java.lang.Process
The ProcessBuilder.start() and Runtime.exec methods create a native process and return an instance of a subclass of Process, which you can use to control and get information about it. The Process class provides methods for inputting from the process, outputting to the process, waiting for the process to complete, checking the process termination status, and destroying (terminating) the process. For example, a native windowing process, a daemon process, a Win16/DOS process under Microsoft Windows, or a shell script process.

By default, the created subprocess does not have its own terminal or console. All its standard I/O (i.e. standard input, standard output, and standard error) processing is redirected to the parent process, but the methods getOutputStream(), getInputStream(), and getErrorStream() can be used to access that information. Use the stream that is retrieved with. The parent process uses these streams to send input to and get output from the subprocess. Some native platforms have a limited buffer size for standard I/O streams, so if a subprocess’s input stream write or stream output read fails, the subprocess is blocked or deadlocked. May be.

If desired, you can also use the methods of the ProcessBuilder class to redirect the input and output of the subprocess.

If there are no more references to the Process object, the subprocess will not be terminated and will continue to run asynchronously.

The execution of the process represented by the Process object does not have to be asynchronous or parallel with the Java process that owns the Process object.

Precautions

deadlock

Some native platforms have a limited buffer size for standard I/O streams, so if a subprocess’s input stream write or stream output read fails, the subprocess will block or deadlock. It may be in a state.

The most important thing to watch out for is the possibility of deadlock.

bad.java


Process p = Runtime.getRuntime().exec("cmd /c dir");
// Make the current thread wait until the process is finished.
// ★★★ The process is blocked if the standard output stream has a lot of output ★★★
p.waitFor();

stream

The ProcessBuilder.start() and Runtime.exec methods create a native process and return an instance of a subclass of Process, which you can use to control and get information about it.

It provides ways to control the process and get information. To avoid the above deadlock, read the standard output stream and standard error stream from the JVM getInputStreamandgetErrorStream method can be used

demo.java


try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())))) (
String line = null;
while ((line = br.readLine()) != null) {
// You don't have to output
}
} catch (IOException e) {
e.printStackTrace();
}

Process termination

If there are no more references to the Process object, the subprocess will not be terminated and will continue to run asynchronously.

Given the description in the API Docs, after using the Process object, I should be able to free the Process object from java’s GC, but just differently, I’m still running. So it’s better to call the destroy() method.

bad.java


Process p = Runtime.getRuntime().exec("cmd /c dir");
// p.destroy(); ★★★ Do not finish ★★★

Sample code

Process sample

MainTest.java


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

//sample
public class MainTest {

public static void main(String[] args) throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec("cmd /c cd bin && java ProcessTest");

// output stream
new StreamThread(p.getInputStream(), "OUTPUT").start();
// error stream
new StreamThread(p.getErrorStream(), "ERROR").start();

// get process execution result
int result = p.waitFor();
p.destroy();

// output data
System.out.println(" ■ execution result code: "+ result);
}
}

// stream thread
class StreamThread extends Thread {
private InputStream in;
private String type;

public StreamThread(InputStream in, String type) {
this.in = in;
this.type = type;
}

@Override
public void run() {
try (BufferedReader br = new BufferedReader(new InputStreamReader(in, "MS932")))) {
String line = null;
while ((line = br.readLine()) != null) {
// output logs
System.out.println(type + ">" + line);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Child process to call (for testing)

ProcessTest.java


public class ProcessTest {

public static void main(String[] args) {
for (int i = 1; i <= 1000; i++) {
// standard output
System.out.println("This is standard output:" + i + "number.");
// standard error
System.err.println("This is standard error: "+ i + "number.");
}
}
}

Tags:

Updated: