Java Process Class
Last modified: April 13, 2025
The java.lang.Process
class provides methods for interacting with
system processes. It allows Java programs to start, control, and communicate
with native operating system processes. This is essential for system-level
programming.
Process objects are created by Runtime.exec
or
ProcessBuilder.start
methods. They represent native processes
running externally to the Java Virtual Machine. The class provides methods to
get input/output streams, wait for completion, and check exit status.
Process Class Methods
The Process class provides several methods for process management. These include methods for I/O stream access, process termination, and status checking. The class is abstract, with platform-specific implementations provided by the JVM.
public abstract class Process { public abstract OutputStream getOutputStream(); public abstract InputStream getInputStream(); public abstract InputStream getErrorStream(); public abstract int waitFor() throws InterruptedException; public abstract int exitValue(); public abstract void destroy(); public Process destroyForcibly(); public boolean isAlive(); public boolean waitFor(long timeout, TimeUnit unit); }
The code above shows the main methods provided by the Process class. These methods allow control over external processes and communication through standard streams. Modern Java versions have added more methods for better process control.
Basic Process Execution
This example demonstrates how to execute a simple system command and wait for
its completion. We use Runtime.getRuntime().exec
to start the
process. The waitFor
method blocks until the process completes.
package com.zetcode; import java.io.IOException; public class Main { public static void main(String[] args) { try { // Execute a system command Process process = Runtime.getRuntime().exec("notepad.exe"); // Wait for the process to complete int exitCode = process.waitFor(); System.out.println("Process exited with code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
In this example, we launch Windows Notepad and wait for it to close. The
waitFor
method returns the exit code of the process. Note that
this is a blocking call - the Java program will wait until Notepad is closed.
Reading Process Output
This example shows how to read the output of a process. We execute a command that produces output and read it through the process's input stream. This is essential for capturing command results.
package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class Main { public static void main(String[] args) { try { // Execute a command that produces output Process process = Runtime.getRuntime().exec("cmd /c dir"); // Get the input stream of the process InputStream inputStream = process.getInputStream(); BufferedReader reader = new BufferedReader( new InputStreamReader(inputStream)); // Read the output line by line String line; while ((line = reader.readLine()) != null) { System.out.println(line); } // Close resources reader.close(); process.waitFor(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
Here we execute the Windows dir
command and read its output. The
process's standard output is available via getInputStream
. We
wrap this in a BufferedReader for efficient line-by-line reading. Always close
streams when done to prevent resource leaks.
Handling Process Errors
This example demonstrates reading error output from a process. Error output is
available through a separate stream obtained via getErrorStream
.
Proper error handling is crucial for robust process management.
package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class Main { public static void main(String[] args) { try { // Execute a command that might produce errors Process process = Runtime.getRuntime().exec("cmd /c dir nonexistent"); // Read standard output readStream(process.getInputStream(), "OUTPUT"); // Read error output readStream(process.getErrorStream(), "ERROR"); process.waitFor(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } private static void readStream(InputStream inputStream, String type) throws IOException { BufferedReader reader = new BufferedReader( new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { System.out.println(type + ": " + line); } reader.close(); } }
In this example, we attempt to list a nonexistent directory, which generates error output. We read both standard output and error streams separately. The error stream typically contains diagnostic messages when a command fails. Both streams should always be read to prevent process hangs.
Writing to Process Input
This example shows how to write data to a process's input stream. Some programs accept input through their standard input. We demonstrate this by communicating with a Python interpreter.
package com.zetcode; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; public class Main { public static void main(String[] args) { try { // Start Python interpreter Process process = Runtime.getRuntime().exec("python"); // Get the output stream to write to the process OutputStream outputStream = process.getOutputStream(); BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(outputStream)); // Write Python commands to the process writer.write("print(2 + 3)\n"); writer.write("exit()\n"); writer.flush(); // Read the output readStream(process.getInputStream(), "PYTHON OUTPUT"); process.waitFor(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } private static void readStream(java.io.InputStream inputStream, String type) throws IOException { java.io.BufferedReader reader = new java.io.BufferedReader( new java.io.InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { System.out.println(type + ": " + line); } reader.close(); } }
Here we start a Python interpreter and send it commands through its standard
input. We obtain the output stream via getOutputStream
and write
Python code to it. After writing, we must flush the stream to ensure the data
is sent. The Python output is then read from the input stream.
ProcessBuilder Example
This example demonstrates the modern ProcessBuilder
approach for
process creation. ProcessBuilder provides more control over process creation
than Runtime.exec(). It allows setting environment variables and working
directory.
package com.zetcode; import java.io.IOException; import java.util.Arrays; public class Main { public static void main(String[] args) { try { // Create ProcessBuilder with command and arguments ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "echo", "Hello, ProcessBuilder!"); // Redirect error stream to standard output pb.redirectErrorStream(true); // Start the process Process process = pb.start(); // Read the combined output readStream(process.getInputStream(), "OUTPUT"); int exitCode = process.waitFor(); System.out.println("Exit code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } private static void readStream(java.io.InputStream inputStream, String type) throws IOException { java.io.BufferedReader reader = new java.io.BufferedReader( new java.io.InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { System.out.println(type + ": " + line); } reader.close(); } }
This example uses ProcessBuilder to execute a command with arguments. We set
redirectErrorStream(true)
to merge error output with standard
output. ProcessBuilder is preferred over Runtime.exec() for its flexibility and
better handling of command arguments. It automatically handles argument quoting
and splitting.
Checking Process Status
This example shows how to check if a process is still running and get its exit
value. The isAlive
method checks process status, while
exitValue
gets the exit code if the process has terminated.
package com.zetcode; import java.io.IOException; public class Main { public static void main(String[] args) { try { // Start a long-running process Process process = Runtime.getRuntime().exec("ping -n 5 localhost"); // Check process status periodically for (int i = 0; i < 10; i++) { if (process.isAlive()) { System.out.println("Process is still running..."); } else { System.out.println("Process exited with code: " + process.exitValue()); break; } Thread.sleep(1000); } // If still running after 10 seconds, destroy it if (process.isAlive()) { System.out.println("Terminating process..."); process.destroy(); } } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
Here we start a ping command that runs for about 5 seconds. We periodically
check its status using isAlive
. If the process is still running
after 10 seconds, we terminate it with destroy
. Note that
exitValue
throws an exception if called on a running process.
Destroying Processes
This example demonstrates different ways to terminate a process. The
destroy
method requests graceful termination, while
destroyForcibly
attempts forceful termination if needed.
package com.zetcode; import java.io.IOException; public class Main { public static void main(String[] args) { try { // Start a process that will run indefinitely Process process = Runtime.getRuntime().exec("notepad.exe"); System.out.println("Process started. Waiting 5 seconds..."); Thread.sleep(5000); // Try to destroy the process gracefully System.out.println("Attempting to destroy process..."); process.destroy(); // Wait a bit to see if it terminates Thread.sleep(1000); if (process.isAlive()) { System.out.println("Process still alive. Forcing termination..."); Process forced = process.destroyForcibly(); forced.waitFor(); System.out.println("Forced termination complete."); } else { System.out.println("Process terminated gracefully."); } } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
In this example, we start Notepad and attempt to close it programmatically.
First we try destroy
for graceful termination. If the process
is still alive after a second, we use destroyForcibly
. The
destroyForcibly
method returns a Process object that can be
used to wait for termination. This provides more control over process
termination.
Source
Java Process Class Documentation
In this article, we've covered the Java Process class with practical examples. Process management is essential for system integration and external command execution. The Process class provides the foundation for these operations in Java.
Author
List all Java tutorials.