(软件构造04)进程API及ProcessBuilder的扩展

本文对第七章进程的内容部分进行一些扩展:
Java中的进程API在Java5之前还是非常原始的,开启一个新进程唯一的方式是调用Runtime.getRuntime().exec() ,直到Java5发布之后,一些更加简明的开启新进程方式被封装到了ProcessBuilder 中。
下面是对一些具体功能的介绍及举例:
1、如何显示当前进程信息:
我们通过调用java.lang.ProcessHandle.Info 可以获取诸多进程的相关信息:
(1)用于开启此进程所使用的命令
(2)命令中传递的参数
(3)开启时间
(4)开启者和总运行时间
下面是具体方式:

@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 或其他) 以上面这些方式来为接口提供实现,以使它们能返回进程的相关信息。
(2)产生进程的信息:
我们也可以获取新产生的进程的相关信息。在此情况下,在我们调用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();

(3)枚举系统中的实时进程
我们可以列举出当前系统中的所有进程,这些进程对当前进程可见。返回的列表是调用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());
      });
}

(4)枚举子进程
这里有两种获取方式:
[1]获取当前进程的直属子级
[2]获取当前进程的所有子级
前者调用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()));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值