JEP 102更新Process API,使得更容易访问过程数据等
JEP 102:Process API更新增强了java.lang.Process类,并将java.lang.ProcessHandle接口引入其嵌套Info接口,以克服通常迫使开发人员使用本地代码的限制; 例如,获取本地进程ID(PID)。这篇文章介绍了这些升级。
加强流程,引入ProcessHandle和Proce
Java 9为抽象Process类添加了几个新方法,可以让您识别直接的子代或后代进程,获取此ProcessPID,返回有关此信息的快照Process,获取完整的未来,以便在Process退出时接收异步通知,以及更多信息:
· Stream<ProcessHandle> children()
· Stream<ProcessHandle> descendants()
· long getPid()
· Proce info()
· CompletableFuture<Process> onExit()
· boolean supportsNormalTermination()
· ProcessHandle toHandle()
这些方法中有一半以上与新ProcessHandle界面配合使用,可以识别和提供对本机进程的控制。例如,toHandle()返回类实现的对象ProcessHandle,并与之相关联Process。ProcessHandle方法如下:
· static Stream<ProcessHandle> allProcesses()
· Stream<ProcessHandle> children()
· int compareTo(ProcessHandle other)
· static ProcessHandle current()
· Stream<ProcessHandle> descendants()
· boolean destroy()
· boolean destroyForcibly()
· long getPid()
· Proce info()
· boolean isAlive()
· static Optional<ProcessHandle> of(long pid)
· CompletableFuture<ProcessHandle> onExit()
· Optional<ProcessHandle> parent()
· boolean supportsNormalTermination()
各种Process方法ProcessHandle通过调用toHandle()随后的方法名称委托给对方。例如,getPid()调用toHandle().getPid()并info()调用toHandle().info()它,返回一个Proce对象。嵌套Info接口提供以下方法:
· Optional<String[]> arguments()
· Optional<String> Command()
· Optional<String> commandLine()
· Optional<Instant> startInstant()
· Optional<Duration> totalCpuDuration()
· Optional<String> user()
每个方法返回一个Java.u可能包含非空对象引用或null 的实例,并且对于避免是有用的java.lang.NullPointerException。您将在后续章节中了解如何使用这些方法以及各种ProcessHandle新Process方法。
获取PID
Process的long getPid()方法返回调用过程的PID。该方法的返回类型long不是int因为PID是无符号整数,最大的正值int约为200万,而Linux可以容纳高达400万的PID。清单1演示getPid()。
清单1.获取和输出PID
import java.io.IOException;
publicclassProcessDemo{
publicstaticvoid main(String[] args)throwsIOException
{
Process p =newProcessBuilder("no;).start();
Sy());
}}
在java.lang.ProcessBuilder类(Java 5中引入)构建的Windows一个进程生成器no程序。start()调用该方法启动no,返回一个Process对象以与新进程交互。Process的getPid()方法随后调用上Process对象和它的值被输出。
产生过程的旧方式
在Java 5之前,产生新流程的唯一方法是使用Run().exec()。ProcessBuilder是一个更好的选择。
编译清单1如下:
javac Proce
运行生成的应用程序如下:
java ProcessDemo
我观察到一个新的窗口no以及从运行到运行的不同的整数。以下是一个例子:
9480
从进程句柄获取PID
如果你有一个ProcessHandle对象,可以通过调用获得其相关联的过程的PID ProcessHandle的long getPid()方法。
也许你想知道getPid()当进程无法启动或在调用此方法之前终止时会发生什么。在第一种情况下,start()抛出java.io.IOException。在第二种情况下,getPid()过程终止后继续返回PID。
获取进程信息
Proce定义了返回过程信息的几种方法,例如进程的可执行路径名,进程的开始时间和进程的用户。清单2显示了一个应用程序的源代码,该应用程序将当前进程的这个信息和其他信息转储到标准输出。
清单2.获取并输出过程信息
import java.io.IOException;
import java.;import java.;
publicclassProcessDemo{
publicstaticvoid main(String[] args)
throwsInterruptedException,IOException
{
dumpProcessInfo());
Process p =newProcessBuilder("no;,"C:\\temp\\names.txt").start();
dumpProcessInfo());
p.waitFor();
dumpProcessInfo());
}
staticvoid dumpProcessInfo(ProcessHandle ph)
{
Sy("PROCESS INFORMATION");
Sy("===================");
Sy("Process id: %d%n", ());
Proce info = ();
Sy("Command: %s%n", in().orElse(""));
String[] args = in().orElse(newString[]{});
Sy("Arguments:");
for(String arg: args)
Sy(" %s%n", arg);
Sy("Command line: %s%n", inLine().orElse(""));
Sy("Start time: %s%n",
in().orElse()).toString());
Sy("Run time duration: %sms%n",
in()
.orElse(0)).toMillis());
Sy("Owner: %s%n", in().orElse(""));
Sy();
}}
main()首先调用Proce()获取当前进程的句柄并将此句柄传递给dumpProcessInfo()调用以转储有关此进程的信息。它接下来将启动no,倾倒其过程信息。等待no终止后,再次main()转储其信息。
dumpProcessInfo()首先输出一个报头,输出PID,并获取进程句柄的Info对象。接下来,它调用command()和其他Info方法,输出它们的值。如果方法返回null(因为信息不可用),则返回传递给Optional's orElse()方法的值。
编译清单2并运行生成的应用程序。我观察到一个新窗口no,并从一个运行中观察到以下输出:
PROCESS INFORMATION
===================
Process id: 1140
Command: C:\PROGRA~1\Java\jdk-9\bin\java.exe
Arguments:
Command line:
Start time: 2017-03-02T22:24:40.998Z
Run time duration: 890ms
Owner: jeff\jeffrey
PROCESS INFORMATION
===================
Process id: 5516
Command: C:\Windows\System32\no
Arguments:
Command line:
Start time: 2017-03-02T22:24:41.763Z
Run time duration: 0ms
Owner: jeff\jeffrey
PROCESS INFORMATION
===================
Process id: 5516
Command:
Arguments:
Command line:
Start time: 2017-03-02T22:24:41.763Z
Run time duration: 234ms
Owner: jeff\jeffrey
第三PROCESS INFORMATION部分在窗口被关闭之前不会出现。Info的arguments()方法不返回C:\temp\names.txt命令行参数,可能是因为信息不可用,或者可能是由于错误。过程终止后,command()返回null。最后,commandLine()返回null command()或arguments()返回null。
获取有关所有进程的信息
ProcessHandle该allProcesses()方法返回描述当前进程可见的所有进程(即进程调用allProcesses())的进程句柄的Java 8 Streams API流。清单3的应用程序源代码使用Streams获取这些句柄,并且对于前四个句柄中的每个句柄,都会转储有关进程的信息。
清单3.获取并输出有关当前进程可见的四个进程的信息
import java.io.IOException;
import java.;import java.;
publicclassProcessDemo{
publicstaticvoid main(String[] args)
{
Proce()
.filter(ph -> ().command().isPresent())
.limit(4)
.forEach((process)-> dumpProcessInfo(process));
}
staticvoid dumpProcessInfo(ProcessHandle ph)
{
Sy("PROCESS INFORMATION");
Sy("===================");
Sy("Process id: %d%n", ());
Proce info = ();
Sy("Command: %s%n", in().orElse(""));
String[] args = in().orElse(newString[]{});
Sy("Arguments:");
for(String arg: args)
Sy(" %s%n", arg);
Sy("Command line: %s%n", inLine().orElse(""));
Sy("Start time: %s%n",
in().orElse()).toString());
Sy("Run time duration: %sms%n",
in()
.orElse(0)).toMillis());
Sy("Owner: %s%n", in().orElse(""));
Sy();
}}
main()调用allProcesses()并链接生成的进程处理流到一个过滤器,该过滤器产生一个新的进程流程流,其中存在进程可执行路径名。(在我的平台上,当进程已经终止时,路径名不存在)。limit(4)调用产生一个不超过四个进程句柄的截断流。最后,forEach()调用调用dumpProcessInfo()每个进程句柄。
编译清单3并运行生成的应用程序。我观察到一次运行的跟随输出:
PROCESS INFORMATION
===================
Process id: 8036
Command: C:\Windows\ex
Arguments:
Command line:
Start time: 2017-03-02T16:21:14.436Z
Run time duration: 299328ms
Owner: jeff\jeffrey
PROCESS INFORMATION
===================
Process id: 10200
Command: C:\Windows\System32\dll
Arguments:
Command line:
Start time: 2017-03-02T16:21:16.255Z
Run time duration: 2000ms
Owner: jeff\jeffrey
PROCESS INFORMATION
===================
Process id: 1544
Command: C:\Program Files (x86)\WNSS\WNSS.exe
Arguments:
Command line:
Start time: 2017-03-02T16:21:21.708Z
Run time duration: 862375ms
Owner: jeff\jeffrey
PROCESS INFORMATION
===================
Process id: 8156
Command: C:\Users\jeffrey\AppData\Local\SweetLabs App Platform\Engine\ServiceHo
Arguments:
Command line:
Start time: 2017-03-02T16:21:24.302Z
Run time duration: 2468ms
Owner: jeff\jeffrey
ProcessHandle的children()和descendents()方法的行为类似,allProcesses()不同之处在于他们是不static和,分别,返回过程中的当前进程的句柄的直接儿童和儿童直接加上他们的后裔(和他们的后裔,等等)。
触发流程终止操作
最后ProcessHandle的onExit()方法,可以为一个线程使用此方法的返回java.u对象时触发操作的过程中他们赖以终止同步或异步运行。查看清单4。
清单4.当进程终止时,获取和输出进程的PID
import java.io.IOException;
import java.u;import java.u;
publicclassProcessDemo{
publicstaticvoid main(String[] args)
throwsExecutionException,InterruptedException,IOException
{
Process p =newProcessBuilder("no;).start();
ProcessHandle ph = p.toHandle();
CompletableFuture<ProcessHandle> onExit = ();
onExit.get();
onExit.thenAccept(ph_ ->Sy("PID %d terminated%n",
()));
}}
main()首先创建并启动一个no进程。接下来,它获取此过程的句柄,并使用此句柄来获取该过程的完整的未来。该onExit.get()调用导致main()等待进程终止,此时thenAccept()执行其lambda,产生类似于此处显示的输出:
PID 7460 terminated
结论
Java 9的Process API增强是Java早期应用和受欢迎的补充。虽然我已经完成了对这些增强功能的介绍,但还有更多的探索。例如,检查出Process的和ProcessHandle的supportsNormalTermination()方法,和ProcessHandle的parent()方法。