Java Process API Improvements in Java 9: Managing OS Processes with Enhanced Features

Explore the significant improvements made to the Process API in Java 9. The ProcessHandle class now provides detailed process information, such as process ID, CPU time, arguments, and more. Learn how the new onExit method enables asynchronous actions when a process exits, and discover how to spawn new processes using the ProcessBuilder class.



Java - Process API Improvements

In Java 9, the Process API, responsible for controlling and managing operating system processes, underwent significant improvements. The ProcessHandle class now provides details such as the process's native process ID, start time, accumulated CPU time, arguments, command, user, parent process, and descendants. The ProcessHandle class also includes methods to check process liveness and to destroy processes. Additionally, it features an onExit method that uses CompletableFuture to perform actions asynchronously when a process exits.

Spawning a New Process Example

In this example, we create a new process for Notepad and start it using ProcessBuilder. We retrieve the process information of the newly spawned process using the ProcessHandle.Info interface.

Example

package com.tutorialsarena;

import java.time.ZoneId;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.io.IOException;

public class Tester {
public static void main(String[] args) throws IOException {
    ProcessBuilder pb = new ProcessBuilder("notepad.exe");
    String np = "Not Present";
    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(np));
    System.out.printf("Command line : %s%n", info.commandLine().orElse(np));

    System.out.printf("Start time: %s%n",
        info.startInstant().map(i -> i.atZone(ZoneId.systemDefault())
        .toLocalDateTime().toString()).orElse(np));

    System.out.printf("Arguments : %s%n",
        info.arguments().map(a -> Stream.of(a).collect(
        Collectors.joining(" "))).orElse(np));

    System.out.printf("User : %s%n", info.user().orElse(np));
} 
}

Output

Process ID : 5580
Command name : C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2401.26.0_x64__8wekyb3d8bbwe\Notepad\Notepad.exe
Command line : Not Present
Start time: 2024-04-02T17:07:14.305
Arguments : Not Present
User : DESKTOP\tutorialsarena

Getting Current Process Information Example

In this example, we retrieve information about the current process using the ProcessHandle.current() method. The ProcessHandle.Info interface is used to get the process information of the current process.

Example

package com.tutorialsarena;

import java.time.ZoneId;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.io.IOException;

public class Tester {
public static void main(String[] args) throws IOException {
    String np = "Not Present";
    ProcessHandle currentProcess = ProcessHandle.current();
    ProcessHandle.Info info = currentProcess.info();
    System.out.printf("Process ID : %s%n", currentProcess.pid());
    System.out.printf("Command name : %s%n", info.command().orElse(np));
    System.out.printf("Command line : %s%n", info.commandLine().orElse(np));

    System.out.printf("Start time: %s%n",
        info.startInstant().map(i -> i.atZone(ZoneId.systemDefault())
        .toLocalDateTime().toString()).orElse(np));

    System.out.printf("Arguments : %s%n",
        info.arguments().map(a -> Stream.of(a).collect(
        Collectors.joining(" "))).orElse(np));

    System.out.printf("User : %s%n", info.user().orElse(np));
} 
}

Output

Process ID : 5352
Command name : C:\Program Files\Java\jdk-21\bin\javaw.exe
Command line : Not Present
Start time: 2024-04-02T17:09:17.902
Arguments : Not Present
User : DESKTOP-DTHL8BI\tutorialsarena

Getting Child Processes Example

In this example, we obtain the current process's child processes using the ProcessHandle.current().children() method. We retrieve the process information of the child processes using the ProcessHandle.Info interface.

Example

package com.tutorialsarena;

import java.io.IOException;
import java.util.stream.Stream;

public class Tester {
public static void main(String[] args) throws IOException {
    for (int i = 0; i < 3; i++) {
        ProcessBuilder processBuilder
        = new ProcessBuilder("java.exe", "-version");
        processBuilder.inheritIO().start();
    }
    Stream childProcesses = ProcessHandle.current().children();
    String np = "Not Present";
    childProcesses.filter(ProcessHandle::isAlive).forEach(
        childProcess ->{
        System.out.printf("Process ID : %s%n", childProcess.pid());
        System.out.printf("Command name : %s%n", childProcess.info().command().orElse(np));
        System.out.printf("Command line : %s%n", childProcess.info().commandLine().orElse(np));
        }
    );
} 
}

Output

Process ID : 5420
Command name : C:\Program Files\Java\jdk-21\bin\java.exe
Command line : Not Present
Process ID : 15796
Command name : C:\Program Files\Java\jdk-21\bin\java.exe
Command line : Not Present
Process ID : 14180
Command name : C:\Program Files\Java\jdk-21\bin\java.exe
Command line : Not Present
java version "21.0.2" 2024-01-16 LTS
Java(TM) SE Runtime Environment (build 21.0.2+13-LTS-58)
Java HotSpot(TM) 64-Bit Server VM (build 21.0.2+13-LTS-58, mixed mode, sharing)