© Fu Cheng 2018

Fu Cheng, Exploring Java 9, https://doi.org/10.1007/978-1-4842-3330-6_5

5. The Process API

Fu Cheng

(1)Auckland, New Zealand

The Java Process API allows developers to create and manage native processes. You can now use the java.lang.ProcessBuilder from JDK 5 to create processes and redirect the output and error streams. The new interface java.lang.ProcessHandle in Java 9 allows you to control the native processes created by ProcessBuilder.start().

The ProcessHandle Interface

The fine-grained control provided by ProcessHandle is very useful for long-running processes. Table 5-1 shows the methods of ProcessHandle. With the ProcessHandle interface, you can query the information about the native process and control its life cycle.

Table 5-1. Methods of ProcessHandle

Method

Description

long pid()

Returns the native process ID.

ProcessHandle.Info info()

Returns ProcessHandle.Info, which contains an information snapshot about the process.

boolean isAlive()

Checks if the process is alive.

Optional<ProcessHandle> parent()

Returns the parent process.

Stream<ProcessHandle> children()

Returns all the children processes.

Stream<ProcessHandle> descendants()

Returns all the descendant processes.

boolean destroy()

Kills the process. It returns true when the termination was requested successfully.

boolean destroyForcibly()

Kills the process forcibly. It returns true when the termination was requested successfully.

boolean supportsNormalTermination()

Checks if the process can be terminated normally using destroy().

CompletableFuture<ProcessHandle> onExit()

Returns a CompletableFuture<ProcessHandle> that can be used to run custom actions when the process is terminated.

Most of the methods in Table 5-1 are straightforward. The return value of info() is an object of class ProcessHandle. Info. Table 5-2 shows the methods of ProcessHandle.Info.

Table 5-2. Methods of ProcessHandle.Info

Method

Description

Optional<String[]> arguments()

Returns the arguments passed to the process

Optional<String> command()

Returns the path of the executable of the process

Optional<String> commandLine()

Returns the command line to start the process

Optional<Instant> startInstant()

Returns the start time of the process as java.time.Instant

Optional<Duration> totalCpuDuration()

Returns the total CPU time of the process as java.time.Duration

Optional<String> user()

Returns the user of this process

ProcessHandle also has some static methods to get ProcessHandles related to the current process; see Table 5-3.

Table 5-3. Static Methods of ProcessHandle

Method

Description

ProcessHandle current()

Returns the ProcessHandle of the current process

Optional<ProcessHandle> of(long pid)

Returns the ProcessHandle of an existing process by its PID

Stream<ProcessHandle> allProcesses()

Returns a snapshot of all processes that are visible to the current process

In Listing 5-1, the method printProcessInfo() prints out the information of the current native java process.

Listing 5-1. Printing the Native Process Info
import java.util.Arrays;

public class CurrentProcess {
  public static void main(String[] args) {
    new CurrentProcess().printProcessInfo(ProcessHandle.current());
  }


  private void printProcessInfo(final ProcessHandle processHandle) {
    final ProcessHandle.Info info = processHandle.info();
    System.out.println("Process info =>");
    System.out.format("PID: %s%n", processHandle.pid());
    info.arguments().ifPresent(args ->
      System.out.format("Arguments: %s%n", Arrays.toString(args)));
    info.command().ifPresent(command ->
      System.out.format("Command: %s%n", command));
    info.commandLine().ifPresent(commandLine ->
      System.out.format("Command line: %s%n", commandLine));
    info.startInstant().ifPresent(startInstant ->
      System.out.format("Start time: %s%n", startInstant));
    info.totalCpuDuration().ifPresent(cpuDuration ->
      System.out.format("CPU time: %s%n", cpuDuration));
    info.user().ifPresent(user ->
      System.out.format("User: %s%n", user));
  }
}

The output looks like Listing 5-2 when running use java.

Listing 5-2. Output of Info About the Current java Process
Process info =>
PID: 14946
Arguments: [-cp, feature9, io.vividcode.feature9.process.CurrentProcess]
Command: /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home/bin/java
Command line: /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home/bin/java
  -cp feature9 io.vividcode.feature9.process.CurrentProcess
Start time: 2017-05-05T04:01:22.686Z
CPU time: PT0.217612S
User: alexcheng

Process

Process also has several new methods; see Table 5-4. Some of these methods have the same name and functionality as they do in ProcessHandle.

Table 5-4. Methods of Process

Method

Description

long pid()

Returns the native process ID

ProcessHandle.Info info()

Returns ProcessHandle.Info, which contains an information snapshot about the process

boolean isAlive()

Checks if the process is alive

ProcessHandle toHandle()

Returns a ProcessHandle for this process

Stream<ProcessHandle> children()

Returns all the children processes

Stream<ProcessHandle> descendants()

Returns all the descendant processes

boolean supportsNormalTermination()

Checks if the process can be terminated normally using destroy()

CompletableFuture<ProcessHandle> onExit()

Returns a CompletableFuture<ProcessHandle> that can be used to run custom actions when the process is terminated

Managing Long-Running Processes

With the new method onExit() of ProcessHandle, it’s now much easier to manage long-running processes. Listing 5-3 shows a simple example. In the method start(), I create a new process with the command top ( https://linux.die.net/man/1/top ) and it returns the ProcessHandle of the process. In the method waitFor(), I use the method whenCompleteAsync() of the CompletableFuture object returned by onExit() to add a handler that invokes when the process exits. In the handler, I can get the ProcessHandle object of the terminated process. Here I just output the PID of this process. The variable shutdownThread represents a thread that destroys the process after a one-second delay. I can check if the ProcessHandle supports graceful termination using supportsNormalTermination() and try to terminate it gracefully. I use the CountDownLatch to wait for the asynchronous completion handler to finish.

Listing 5-3. Managing Long-Running Processes
public class LongRunningProcess {

  public ProcessHandle start() throws IOException {
    final ProcessBuilder processBuilder = new ProcessBuilder("top")
        .inheritIO();
    return processBuilder.start().toHandle();
  }


  public void waitFor(final ProcessHandle processHandle) {
    final CountDownLatch latch = new CountDownLatch(1);
    processHandle.onExit().whenCompleteAsync((handle, throwable) -> {
      if (throwable == null) {
        System.out.println(handle.pid());
      } else {
        throwable.printStackTrace();
      }
      latch.countDown();
    });
    final Thread shutdownThread = new Thread(() -> {
      try {
        Thread.sleep(1000);
      } catch (final InterruptedException e) {
        e.printStackTrace();
      }
      if (processHandle.supportsNormalTermination()) {
        processHandle.destroy();
      } else {
        processHandle.destroyForcibly();
      }
    });
    shutdownThread.start();
    try {
      shutdownThread.join();
      latch.await();
    } catch (final InterruptedException e) {
      e.printStackTrace();
    }
  }


  public static void main(final String[] args) {
    final LongRunningProcess longRunningProcess = new LongRunningProcess();
    try {
      longRunningProcess.waitFor(longRunningProcess.start());
    } catch (final IOException e) {
      e.printStackTrace();
    }
  }
}

When you run the code in Listing 5-3, you should see the output of top command for about one second, then the PID of the process displays and the program terminates.

Summary

In this chapter, we discussed the new ProcessHandle API that can provide control of native processes. I also showed you how to manage long-running processes using this new API. In next chapter, we’ll discuss the platform logging API and service.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.181.47