- Process class example in java
- Process API Classes and Interfaces
- ProcessBuilder Class
- Process Class
- ProcessHandle Interface
- ProcessHandle.Info Interface
- Creating a Process
- Getting Information About a Process
- Redirecting Output from a Process
- Filtering Processes with Streams
- Handling Processes When They Terminate with the onExit Method
- Controlling Access to Sensitive Process Information
Process class example in java
The Process API lets you start, retrieve information about, and manage native operating system processes.
With this API, you can work with operating system processes as follows:
- Run arbitrary commands:
- Filter running processes
- Redirect output
- Connect heterogeneous commands and shells by scheduling tasks to start when another ends
- Clean up leftover processes
- Run a series of tests
- Log output
- Monitor long-running processes and restart them if they terminate
- Collect usage statistics
Process API Classes and Interfaces
The Process API consists of the classes and interfaces ProcessBuilder , Process , ProcessHandle , and ProcessHandle.Info .
ProcessBuilder Class
The ProcessBuilder class lets you create and start operating system processes.
See Creating a Process for examples on how to create and start a process. The ProcessBuilder class manages various process attributes, which the following table summarizes:
Table 6-1 ProcessBuilder Class Attributes and Related Methods
Process Class
The methods in the Process class let you to control processes started by the methods ProcessBuilder.start and Runtime.exec . The following table summarizes these methods:
The following table summarizes the methods of the Process class.
Table 6-2 Process Class Methods
ProcessHandle Interface
The ProcessHandle interface lets you identify and control native processes. The Process class is different from ProcessHandle because it lets you control processes started only by the methods ProcessBuilder.start and Runtime.exec ; however, the Process class lets you access process input, output, and error streams.
See Filtering Processes with Streams for an example of the ProcessHandle interface. The following table summarizes the methods of this interface:
Table 6-3 ProcessHandle Interface Methods
ProcessHandle.Info Interface
The ProcessHandle.Info interface lets you retrieve information about a process, including processes created by the ProcessBuilder.start method and native processes.
See Getting Information About a Process for an example of the ProcessHandle.Info interface. The following table summarizes the methods in this interface:
Table 6-4 ProcessHandle.Info Interface Methods
Method Description arguments() Returns the arguments of the process as a String array. command() Returns the executable path name of the process. commandLine() Returns the command line of the process. startInstant() Returns the start time of the process. totalCpuDuration() Returns the process’s total accumulated CPU time. user() Returns the user of the process. Creating a Process
To create a process, first specify the attributes of the process, such as the command’s name and its arguments, with the ProcessBuilder class. Then, start the process with the ProcessBuilder.start method, which returns a Process instance.
The following lines create and start a process:
ProcessBuilder pb = new ProcessBuilder("echo", "Hello World!"); Process p = pb.start();
In the following excerpt, the setEnvTest method sets two environment variables, horse and doc , then prints the value of these environment variables (as well as the system environment variable HOME ) with the echo command:
public static void setEnvTest() throws IOException, InterruptedException < ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "echo $horse $dog $HOME").inheritIO(); pb.environment().put("horse", "oats"); pb.environment().put("dog", "treats"); pb.start().waitFor(); >
This method prints the following (assuming that your home directory is /home/admin ):
Getting Information About a Process
The method Process.pid returns the native process ID of the process. The method Process.info returns a ProcessHandle.Info instance, which contains additional information about the process, such as its executable path name, start time, and user.
In the following excerpt, the method getInfoTest starts a process and then prints information about it:
public static void getInfoTest() throws IOException < ProcessBuilder pb = new ProcessBuilder("echo", "Hello World!"); String na = ""; Process p = pb.start(); ProcessHandle.Info info = p.info(); System.out.printf("Process ID: %s%n", p.pid()); System.out.printf("Command name: %s%n", info.command().orElse(na)); System.out.printf("Command line: %s%n", info.commandLine().orElse(na)); System.out.printf("Start time: %s%n", info.startInstant().map((Instant i) -> i .atZone(ZoneId.systemDefault()).toLocalDateTime().toString()) .orElse(na)); System.out.printf("Arguments: %s%n", info.arguments().map( (String[] a) -> Stream.of(a).collect(Collectors.joining(" "))) .orElse(na)); System.out.printf("User: %s%n", info.user().orElse(na)); >
This method prints output similar to the following:
Process ID: 18761 Command name: /usr/bin/echo Command line: echo Hello World! Start time: 2017-05-30T18:52:15.577 Arguments: User: administrator
- The attributes of a process vary by operating system and are not available in all implementations. In addition, information about processes is limited by the operating system privileges of the process making the request.
- All the methods in the interface ProcessHandle.Info return instances of Optional ; always check if the returned value is empty.
Redirecting Output from a Process
By default, a process writes standard output and standard error to pipes. In your application, you can access these pipes through the input streams returned by the methods Process.getOutputStream and Process.getErrorStream . However, before starting the process, you can redirect standard output and standard error to other destinations, such as a file, with the methods redirectOutput and redirectError .
In the following excerpt, the method redirectToFileTest redirects standard input to a file, out.tmp , then prints this file:
public static void redirectToFileTest() throws IOException, InterruptedException < File outFile = new File("out.tmp"); Process p = new ProcessBuilder("ls", "-la") .redirectOutput(outFile) .redirectError(Redirect.INHERIT) .start(); int status = p.waitFor(); if (status == 0) < p = new ProcessBuilder("cat" , outFile.toString()) .inheritIO() .start(); p.waitFor(); >>
The excerpt redirects standard output to the file out.tmp . It redirects standard error to the standard error of the invoking process; the value Redirect.INHERIT specifies that the subprocess I/O source or destination is the same as that of the current process. The call to the inheritIO() method is equivalent to redirectInput(Redirect.INHERIT).redirectOuput(Redirect.INHERIT).redirectError(Redirect.INHERIT) .
Filtering Processes with Streams
The method ProcessHandle.allProcesses returns a stream of all processes visible to the current process. You can filter the ProcessHandle instances of this stream the same way that you filter elements from a collection.
In the following excerpt, the method filterProcessesTest prints information about all the processes owned by the current user, sorted by the process ID of their parent’s process:
public class ProcessTest < // . public static void main(String[] args) < ProcessTest.filterProcessesTest(); >static void filterProcessesTest() < OptionalcurrUser = ProcessHandle.current().info().user(); ProcessHandle.allProcesses() .filter(p1 -> p1.info().user().equals(currUser)) .sorted(ProcessTest::parentComparator) .forEach(ProcessTest::showProcess); > static int parentComparator(ProcessHandle p1, ProcessHandle p2) < long pid1 = p1.parent().map(ph ->ph.pid()).orElse(-1L); long pid2 = p2.parent().map(ph -> ph.pid()).orElse(-1L); return Long.compare(pid1, pid2); > static void showProcess(ProcessHandle ph) < ProcessHandle.Info info = ph.info(); System.out.printf("pid: %d, user: %s, cmd: %s%n", ph.pid(), info.user().orElse("none"), info.command().orElse("none")); >// . >
Note that the allProcesses method is limited by native operating system access controls. Also, because all processes are created and terminated asynchronously, there is no guarantee that a process in the stream is alive or that no other processes may have been created since the call to the allProcesses method.
Handling Processes When They Terminate with the onExit Method
The Process.onExit and ProcessHandle.onExit methods return a CompletableFuture instance, which you can use to schedule tasks when a process terminates. Alternatively, if you want your application to wait for a process to terminate, then you can call onExit().get() .
In the following excerpt, the method startProcessesTest creates three processes and then starts them. Afterward, it calls onExit().thenAccept(onExitMethod) on each of the processes; onExitMethod prints the process ID (PID), exit status, and output of the process.
public class ProcessTest < // . static public void startProcessesTest() throws IOException, InterruptedException < Listgreps = new ArrayList<>(); greps.add(new ProcessBuilder("/bin/sh", "-c", "grep -c \"java\" *")); greps.add(new ProcessBuilder("/bin/sh", "-c", "grep -c \"Process\" *")); greps.add(new ProcessBuilder("/bin/sh", "-c", "grep -c \"onExit\" *")); ProcessTest.startSeveralProcesses (greps, ProcessTest::printGrepResults); System.out.println("\nPress enter to continue . \n"); System.in.read(); > static void startSeveralProcesses ( List pBList, Consumer onExitMethod) throws InterruptedException < System.out.println("Number of processes: " + pBList.size()); pBList.stream().forEach( pb ->< try < Process p = pb.start(); System.out.printf("Start %d, %s%n", p.pid(), p.info().commandLine().orElse("")); p.onExit().thenAccept(onExitMethod); > catch (IOException e) < System.err.println("Exception caught"); e.printStackTrace(); >> ); > static void printGrepResults(Process p) < System.out.printf("Exit %d, status %d%n%s%n%n", p.pid(), p.exitValue(), output(p.getInputStream())); >private static String output(InputStream inputStream) < String s = ""; try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) < s = br.lines().collect(Collectors.joining(System.getProperty("line.separator"))); >catch (IOException e) < System.err.println("Caught IOException"); e.printStackTrace(); >return s; > // . >
The output of the method startProcessesTest is similar to the following. Note that the processes might exit in a different order than the order in which they were started.
Number of processes: 3 Start 12401, /bin/sh -c grep -c "java" * Start 12403, /bin/sh -c grep -c "Process" * Start 12404, /bin/sh -c grep -c "onExit" * Press enter to continue . Exit 12401, status 0 ProcessTest.class:0 ProcessTest.java:16 Exit 12404, status 0 ProcessTest.class:0 ProcessTest.java:8 Exit 12403, status 0 ProcessTest.class:0 ProcessTest.java:38
This method calls the System.in.read() method to prevent the program from terminating before all the processes have exited (and have run the method specified by the thenAccept method).
If you want to wait for a process to terminate before proceeding with the rest of the program, then call onExit().get() :
static void startSeveralProcesses ( List pBList, Consumer onExitMethod) throws InterruptedException < System.out.println("Number of processes: " + pBList.size()); pBList.stream().forEach( pb ->< try < Process p = pb.start(); System.out.printf("Start %d, %s%n", p.pid(), p.info().commandLine().orElse("")); p.onExit().get(); printGrepResults(p); > catch (IOException|InterruptedException|ExecutionException e ) < System.err.println("Exception caught"); e.printStackTrace(); >> ); >
The ComputableFuture class contains a variety of methods that you can call to schedule tasks when a process exits including the following:
- thenApply : Similar to thenAccept , except that it takes a lambda expression of type Function (a lambda expression that returns a value).
- thenRun : Takes a lambda expression of type Runnable (no formal parameters or return value).
- thenApplyAsyc : Runs the specified Function with a thread from ForkJoinPool.commonPool() .
Because ComputableFuture implements the Future interface, this class also contains synchronous methods:
- get(long timeout, TimeUnit unit) : Waits, if necessary, at most the time specified by its arguments for the process to complete.
- isDone : Returns true if the process is completed.
Controlling Access to Sensitive Process Information
Process information may contain sensitive information such as user IDs, paths, and arguments to commands. Control access to process information with a security manager.
When running as a normal application, a ProcessHandle has the same operating system privileges to information about other processes as a native application; however, information about system processes may not be available.
If your application uses the SecurityManager class to implement a security policy, then to enable it to access process information, the security policy must grant RuntimePermission(«manageProcess») . This permission enables native process termination and access to the process ProcessHandle information. Note that this permission enables code to identify and terminate processes that it did not create.
The Security Manager and APIs related to it have been deprecated and are subject to removal in a future release. There is no replacement for the Security Manager. See JEP 411 for discussion and alternatives.