Sunday, February 25, 2018

Java 9: Enhancements to the Process API

Java 9 brings various improvements to the Process API, used for controlling and managing operating system processes.

Getting information about a process

There is a new ProcessHandle class which provides the process's pid, parent and descendants, as well as information about the start time and accumulated CPU time.

jshell> Process p = new ProcessBuilder("stress", "--cpu", "4", "--timeout", "5").start();
p ==> Process[pid=5572, exitValue="not exited"]

jshell> p.pid()
$2 ==> 5572

jshell> p.info().user()
$3 ==> Optional[fahd]

jshell> p.info().command()
$4 ==> Optional[/usr/bin/stress]

jshell> p.info().commandLine()
$5 ==> Optional[/usr/bin/stress --cpu 4 --timeout 120]

jshell> Arrays.toString(p.info().arguments().get())
$6 ==> "[--cpu, 4, --timeout, 120]"

jshell> p.info().startInstant()
$7 ==> Optional[2018-02-25T16:38:56.742Z]

jshell> p.info().totalCpuDuration().get().toMillis()
$8 ==> 0

It's strange that totalCpuDuration always returns 0 (a duration string of "PT0S"), no matter what command I run.

Note that I am invoking the Linux stress command in the example above. This is a useful tool for imposing a certain type of stress (e.g. creating cpu load) on your system.

Listing all running processes

The static ProcessHandle.allProcesses() method returns a stream of all processes visible to the current process.

ProcessHandle.allProcesses()
             .map(ProcessHandle::info)
             .map(ProcessHandle.Info::commandLine)
             .flatMap(Optional::stream)
             .forEach(System.out::println)

Triggering a function when a process exits

The Process.onExit method can be used to schedule a function when a process terminates. This method returns a CompletableFuture, which contains a variety of methods that can be called to schedule functions. Here is an example:

Process proc = new ProcessBuilder("sleep", "10").start();
proc.onExit()
    .thenAccept(p -> System.out.println("Process " + p.pid() + " exited with " + p.exitValue()));

Alternatively, to wait for a process to terminate, you can call Process.onExit().get().