1. An overview of the
The process API in Java was pretty primitive before Java5, and the only way to start a new process was to call Runtime.geTruntime ().exec(), until Java5, when more concise ways to start a new process were packaged into ProcessBuilder.
In Java9, you’ll also have a new way to get information about all the running processes on your current system.
No more words, sneak peek!
2. Information about the current Java process
We by calling Java. Lang. ProcessHandle. The Info you can get a lot of process information:
- Command used to start this process
- The arguments passed in the command
- Open time
- Openers and total running time
Here’s how:
@Test public void givenCurrentProcess_whenInvokeGetInfo_thenSuccess() throws IOException { ProcessHandle processHandle = ProcessHandle.current(a);
ProcessHandle.Info processInfo = processHandle.info(a);
assertNotNull(processHandle.getPid());
assertEquals(false, processInfo.arguments(a).isPresent());
assertEquals(true, processInfo.command(a).isPresent());
assertTrue(processInfo.command(a).get(a).contains("java"));
assertEquals(true, processInfo.startInstant(a).isPresent());
assertEquals(true,
processInfo.totalCpuDuration(a).isPresent());
assertEquals(true, processInfo.user(a).isPresent());
}Copy the code
It is important to note that the Java. Lang. ProcessHandle. The Info is another interface in Java. The lang. ProcessHandle defined in the public interface. JDK vendors (Oracle JDK, Open JDK, Zulu, or others) provide implementations of interfaces in these ways so that they can return information about the process.
3. Generate process information
We can also get information about newly generated processes. In this case, after we call java.lang.process to generate and get a Process, we call the toHandle() method to get an instance of java.lang.Processhandle.
Other details are the same as above:
String javaCmd = ProcessUtils.getJavaCmd(a).getAbsolutePath(a);
ProcessBuilder processBuilder = new ProcessBuilder(javaCmd, "-version");
Process process = processBuilder.inheritIO(a).start(a);
ProcessHandle processHandle = process.toHandle(a);Copy the code
4. Enumerate real-time processes in the system
We can list all the processes in the current system that are visible to the current process. The list returned is a snapshot of when the API was called, so a process may be terminated or a new process may be started at the same time.
We can obtain the ProcessHandle stream using the static method allProcesses() declared in the java.lang.processhandle interface:
@Test
public void givenLiveProcesses_whenInvokeGetInfo_thenSuccess() {
Stream<ProcessHandle> liveProcesses = ProcessHandle.allProcesses(a);
liveProcesses.filter(ProcessHandle::isAlive)
.forEach(ph -> {
assertNotNull(ph.getPid());
assertEquals(true, ph.info(a).command(a).isPresent());
});
}Copy the code
5. Enumerate subprocesses
There are two ways to get it:
- Gets the immediate child of the current process
- Gets all the children of the current process
The former calls children() and the latter calls descendants() :
@Test
public void givenProcess_whenGetChildProcess_thenSuccess()
throws IOException{
int childProcessCount = 5;
for (int i = 0; i < childProcessCount; i++){
String javaCmd = ProcessUtils.getJavaCmd(a).getAbsolutePath(a);
ProcessBuilder processBuilder
= new ProcessBuilder(javaCmd, "-version");
processBuilder.inheritIO(a).start(a);
}
Stream<ProcessHandle> children
= ProcessHandle.current(a).children(a);
children.filter(ProcessHandle::isAlive)
.forEach(ph -> log.info("PID: {}, Cmd: {}",
ph.getPid(), ph.info(a).command()));
// and for descendants
Stream<ProcessHandle> descendants
= ProcessHandle.current(a).descendants(a);
descendants.filter(ProcessHandle::isAlive)
.forEach(ph -> log.info("PID: {}, Cmd: {}",
ph.getPid(), ph.info(a).command()));
}Copy the code
6. Related operations are triggered when the process terminates
Sometimes there is a need to trigger actions when a process terminates, which can be met by calling the onExit() method declared in the java.lang.processhandle interface. This method returns the CompletableFuture, which can trigger some action when the CompletableFuture completes.
The CompletableFuture indicates that a process has completed, and it doesn’t care how the process completed. Wait for the process to complete by explicitly calling its get() method:
@Test
public void givenProcess_whenAddExitCallback_thenSuccess()
throws Exception {
String javaCmd = ProcessUtils.getJavaCmd(a).getAbsolutePath(a);
ProcessBuilder processBuilder
= new ProcessBuilder(javaCmd, "-version");
Process process = processBuilder.inheritIO(a).start(a);
ProcessHandle processHandle = process.toHandle(a);
log.info("PID: {} has started", processHandle.getPid());
CompletableFuture<ProcessHandle> onProcessExit
= processHandle.onExit(a);
onProcessExit.get(a);
assertEquals(false, processHandle.isAlive());
onProcessExit.thenAccept(ph -> {
log.info("PID: {} has stopped", ph.getPid());
});
}Copy the code
Of course, the onExit() method can also be called through the java.lang.process interface.
Original: www.baeldung.com/java-9-proc…