Java9 进程API
Posted Lovnx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java9 进程API相关的知识,希望对你有一定的参考价值。
1. 概述
Java中的进程API在Java5之前还是非常原始的,开启一个新进程唯一的方式是调用Runtime.getRuntime().exec()
,直到Java5发布之后,一些更加简明的开启新进程方式被封装到了ProcessBuilder
中。
而在Java9中,你也将能使用一种全新的方式来获取当前系统所有正在运行的进程的相关信息。
话不多说,先睹为快!
2. 当前Java进程的信息
我们通过调用java.lang.ProcessHandle.Info
可以获取诸多进程的相关信息:
- 用于开启此进程所使用的命令
- 命令中传递的参数
- 开启时间
- 开启者和总运行时间
下面是具体方式:
@Test
public void givenCurrentProcess_whenInvokeGetInfo_thenSuccess()
throws IOException
ProcessHandle processHandle = ProcessHandle.current();
ProcessHandle.Info processInfo = processHandle.info();
assertNotNull(processHandle.getPid());
assertEquals(false, processInfo.arguments().isPresent());
assertEquals(true, processInfo.command().isPresent());
assertTrue(processInfo.command().get().contains("java"));
assertEquals(true, processInfo.startInstant().isPresent());
assertEquals(true,
processInfo.totalCpuDuration().isPresent());
assertEquals(true, processInfo.user().isPresent());
需要注意的是,java.lang.ProcessHandle.Info
是在另一个接口java.lang.ProcessHandle
中定义的公共接口。JDK 供应商(Oracle JDK, Open JDK, Zulu 或其他) 以上面这些方式来为接口提供实现,以使它们能返回进程的相关信息。
3. 产生进程的信息
我们也可以获取新产生的进程的相关信息。在此情况下,在我们调用java.lang.Process
生成并获取一个进程之后,我们调用toHandle()
方法来获取java.lang.ProcessHandle
的实例。
其他细节与上例一致:
String javaCmd = ProcessUtils.getJavaCmd().getAbsolutePath();
ProcessBuilder processBuilder = new ProcessBuilder(javaCmd, "-version");
Process process = processBuilder.inheritIO().start();
ProcessHandle processHandle = process.toHandle();
4. 枚举系统中的实时进程
我们可以列举出当前系统中的所有进程,这些进程对当前进程可见。返回的列表是调用API时的快照,因此在操作的同时可能有进程终止,也可能有新的进程被开启。
我们可以使用java.lang.ProcessHandle
接口中声明的静态方法allProcesses()
来获取ProcessHandle
流:
@Test
public void givenLiveProcesses_whenInvokeGetInfo_thenSuccess()
Stream<ProcessHandle> liveProcesses = ProcessHandle.allProcesses();
liveProcesses.filter(ProcessHandle::isAlive)
.forEach(ph ->
assertNotNull(ph.getPid());
assertEquals(true, ph.info()
.command()
.isPresent());
);
5. 枚举子进程
这里有两种获取方式:
- 获取当前进程的直属子级
- 获取当前进程的所有子级
前者调用children()
,后者调用descendants()
:
@Test
public void givenProcess_whenGetChildProcess_thenSuccess()
throws IOException
int childProcessCount = 5;
for (int i = 0; i < childProcessCount; i++)
String javaCmd = ProcessUtils.getJavaCmd()
.getAbsolutePath();
ProcessBuilder processBuilder
= new ProcessBuilder(javaCmd, "-version");
processBuilder.inheritIO().start();
Stream<ProcessHandle> children
= ProcessHandle.current().children();
children.filter(ProcessHandle::isAlive)
.forEach(ph -> log.info("PID: , Cmd: ",
ph.getPid(), ph.info().command()));
// and for descendants
Stream<ProcessHandle> descendants
= ProcessHandle.current().descendants();
descendants.filter(ProcessHandle::isAlive)
.forEach(ph -> log.info("PID: , Cmd: ",
ph.getPid(), ph.info().command()));
6. 进程终止时触发相关操作
有时候有需求需要我们在某个进程终止时触发某些操作,我们可以通过调用java.lang.ProcessHandle
接口中声明的onExit()
方法来满足。 该方法返回CompletableFuture
,可以在CompletableFuture
完成时触发某些操作。
CompletableFuture
表示一个进程已经完成,它不关心进程以何种方式完成。通过显式调用它的get()
方法来等待进程完成:
@Test
public void givenProcess_whenAddExitCallback_thenSuccess()
throws Exception
String javaCmd = ProcessUtils.getJavaCmd()
.getAbsolutePath();
ProcessBuilder processBuilder
= new ProcessBuilder(javaCmd, "-version");
Process process = processBuilder.inheritIO()
.start();
ProcessHandle processHandle = process.toHandle();
log.info("PID: has started", processHandle.getPid());
CompletableFuture<ProcessHandle> onProcessExit
= processHandle.onExit();
onProcessExit.get();
assertEquals(false, processHandle.isAlive());
onProcessExit.thenAccept(ph ->
log.info("PID: has stopped", ph.getPid());
);
当然,也可以通过java.lang.Process
接口来调用onExit()
方法。
原文:http://www.baeldung.com/java-9-process-api
以上是关于Java9 进程API的主要内容,如果未能解决你的问题,请参考以下文章