Официально представлен новый процесс API в JEP 102 для улучшенияjava.lang.Process
класс, и представитьjava.lang.ProcessHandle
и его вложенные интерфейсыInfo
Чтобы позволить разработчикам избежать дилеммы, связанной с необходимостью время от времени использовать собственный код для получения PID собственного процесса. В этой статье подробно описаны эти новые функции.
1. ProcessHandle и ProcessHandle.Info
Java 9 абстрактнаProcess
В классе добавлено множество новых методов, с помощью которых можно идентифицировать непосредственные дочерние процессы и все процессы-потомки, получить PID процесса, получить снимок процесса, получитьCompletableFuture
Экземпляр для получения асинхронных уведомлений об окончании процесса и получения дополнительных возможностей:
Stream<ProcessHandle> children()
Stream<ProcessHandle> descendants()
long getPid()
ProcessHandle.Info info()
CompletableFuture<Process> onExit()
boolean supportsNormalTermination()
ProcessHandle toHandle()
Видно, что более половины методов требуют сочетанияProcessHandle
интерфейс для использования,ProcessHandle
Интерфейсы могут идентифицировать локальные процессы и управлять ими. Например,toHandle()
метод может возвращатьProcessHandle
Конкретный объект реализации и связанный с ним процесс,ProcessHandle
Метод, объявленный в, выглядит следующим образом:
static Stream<ProcessHandle> allProcesses()
Stream<ProcessHandle> children()
int compareTo(ProcessHandle other)
static ProcessHandle current()
Stream<ProcessHandle> descendants()
boolean destroy()
boolean destroyForcibly()
long getPid()
ProcessHandle.Info info()
boolean isAlive()
static Optional<ProcessHandle> of(long pid)
CompletableFuture<ProcessHandle> onExit()
Optional<ProcessHandle> parent()
boolean supportsNormalTermination()
Process
Метод в имени метода вызываетсяtoHandle()
метод, делегированныйProcessHandle
интерфейс. Например, вызовgetPid()
это вызовtoHandle().getPid()
,передачаinfo()
это вызовtoHandle().info()
, который возвращаетProcessHandle.Info
объект, его вложенный интерфейсInfo
Предоставляет следующий список методов:
Optional<String[]> arguments()
Optional<String> command()
Optional<String> commandLine()
Optional<Instant> startInstant()
Optional<Duration> totalCpuDuration()
Optional<String> user()
каждый метод возвращаетjava.util.Optional
Экземпляры, которые могут быть нулевыми или ненулевыми ссылками на объекты, мы все знаем, что этого можно эффективно избежать.java.lang.NullPointerException
. Ниже вы узнаете больше об этих методах.
2. Получить ПИД
Process
изlong getPid()
Метод возвращает PID определенного процесса. Причина, по которой возвращаемое значение имеет тип long вместо int, заключается в том, что PID является целым числом без знака. Наибольшее положительное целое число равно примерно 2 миллионам, но система Linux может содержать около 4 миллионов идентификаторов PID.
Вот как получить PID:
import java.io.IOException;
public class ProcessDemo
{
public static void main(String[] args) throws IOException
{
Process p = new ProcessBuilder("notepad.exe").start();
System.out.println(p.getPid());
}
}
java.lang.ProcessBuilder
Класс (представленный в Java 5) создает процесс для программы Windows notepad.exe. использоватьstart()
Метод открывается и возвращаетProcess
объект для взаимодействия с новым процессом. а потом позвониgetPid()
метод получения PID.
Как создавать новые процессы
До Java 5 единственным способом создать новый процесс было использованиеRuntime.getRuntime().exec()
, и теперь лучше использоватьProcessBuilder
.
Скомпилируйте ProcessDemo.java:
javac ProcessDemo.java
Запустите ProcessDemo.java:
java ProcessDemo
Вы можете увидеть новый процесс в диспетчере процессовnotepad.exe
работает и может видеть его PID.
9480 或者其他无符号整型
Получить PID из дескриптора процесса
если естьProcessHandle
объект, доступ к которому можно получить, вызвавgetPid()
чтобы получить PID.
Вам должно быть интересно, что произойдет, если процесс не запустится или неожиданно завершится при вызове этого метода.start()
бросатьjava.io.IOException
, второй случай,getPid()
Продолжайте возвращать PID после завершения процесса.
3. Получите информацию о процессе
ProcessHandle.Info
Определены некоторые методы, возвращающие информацию о процессе, такую как путь к исполняемому файлу процесса, время запуска процесса, имя пользователя, запустившего процесс, и т. д.
Следующий код запускает процесс и выводит некоторую информацию о процессе:
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
public class ProcessDemo
{
public static void main(String[] args)
throws InterruptedException, IOException
{
dumpProcessInfo(ProcessHandle.current());
Process p = new ProcessBuilder("notepad.exe", "C:\\temp\\names.txt").start();
dumpProcessInfo(p.toHandle());
p.waitFor();
dumpProcessInfo(p.toHandle());
}
static void dumpProcessInfo(ProcessHandle ph)
{
System.out.println("PROCESS INFORMATION");
System.out.println("===================");
System.out.printf("Process id: %d%n", ph.getPid());
ProcessHandle.Info info = ph.info();
System.out.printf("Command: %s%n", info.command().orElse(""));
String[] args = info.arguments().orElse(new String[]{});
System.out.println("Arguments:");
for (String arg: args)
System.out.printf(" %s%n", arg);
System.out.printf("Command line: %s%n", info.commandLine().orElse(""));
System.out.printf("Start time: %s%n",
info.startInstant().orElse(Instant.now()).toString());
System.out.printf("Run time duration: %sms%n",
info.totalCpuDuration()
.orElse(Duration.ofMillis(0)).toMillis());
System.out.printf("Owner: %s%n", info.user().orElse(""));
System.out.println();
}
}
существуетmain()
метод вызывается первымProcessHandle.current()
чтобы получить дескриптор текущего процесса, затем используйтеdumpProcessInfo()
метод для вывода подробной информации о процессе создания дампа. Следующий стартnotepad.exe
, и дамп его информации о процессе. Подожди покаnotepad.exe
После завершения он снова сбрасывает свою информацию.
dumpProcessInfo()
Метод сначала выводит идентификационную информацию заголовка, затем выводит PID, а затем получаетProcessHandle.Info
Цитировать. Далее звонитеcommand()
и другиеInfo
методы, выведите их значения. Если метод возвращает null (поскольку информация недоступна), передатьOptional
изorElse()
способ возврата информации.
Вот вывод, во время которого видно окно блокнота:
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\notepad.exe
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
ИНФОРМАЦИЯ О ПРОЦЕССЕ в третьей части не появлялась, пока не исчез интерфейс блокнота. Метод arguments() из Info не печатает командную строку в файл C:\temp\names.txt либо потому, что информация в данный момент недоступна, либо из-за ошибки. После завершения процесса метод command() возвращает null. Наконец, когда метод command() или метод arguments() возвращает значение null, метод commandLine() также возвращает значение null.
4. Получить информацию обо всех процессах
ProcessHandle
серединаallProcesses()
Метод возвращает все видимые дескрипторы процессов в текущей системе наподобие Stream API в Java8. В следующем коде показано, как использовать Stream для получения дескриптора процесса, получения первых четырех процессов и вывода их информации.
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
public class ProcessDemo
{
public static void main(String[] args)
{
ProcessHandle.allProcesses()
.filter(ph -> ph.info().command().isPresent())
.limit(4)
.forEach((process) -> dumpProcessInfo(process));
}
static void dumpProcessInfo(ProcessHandle ph)
{
System.out.println("PROCESS INFORMATION");
System.out.println("===================");
System.out.printf("Process id: %d%n", ph.getPid());
ProcessHandle.Info info = ph.info();
System.out.printf("Command: %s%n", info.command().orElse(""));
String[] args = info.arguments().orElse(new String[]{});
System.out.println("Arguments:");
for (String arg: args)
System.out.printf(" %s%n", arg);
System.out.printf("Command line: %s%n", info.commandLine().orElse(""));
System.out.printf("Start time: %s%n",
info.startInstant().orElse(Instant.now()).toString());
System.out.printf("Run time duration: %sms%n",
info.totalCpuDuration()
.orElse(Duration.ofMillis(0)).toMillis());
System.out.printf("Owner: %s%n", info.user().orElse(""));
System.out.println();
}
}
Метод allProcesses() вызывается в методе main() для явного импорта потока дескриптора потока из имени пути в фильтр, а затем обертывания его в новый поток дескриптора потока. (В моей среде путь не распечатывается, когда процесс завершается) Метод limit(4) может перехватить не более 4 процессов, чтобы поместить их в поток. Наконец, повторите всю их информацию.
Вот результат:
PROCESS INFORMATION
===================
Process id: 8036
Command: C:\Windows\explorer.exe
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\dllhost.exe
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\ServiceHostAppUpdater.exe
Arguments:
Command line:
Start time: 2017-03-02T16:21:24.302Z
Run time duration: 2468ms
Owner: jeff\jeffrey
Метод Children() и метод потомков() ProcessHandle очень похожи на метод allProcesses() f, за исключением того, что они являются статическими методами, а тип возвращаемого значения отличается, между ними существует установленная принадлежность, Children() — это A подмножество потомков (), потомки () являются подмножеством всех процессов ().
5. Триггерный механизм завершения процесса
Наконец, метод onExit() класса ProcessHandle возвращает java.util.concurrent.CompletableFuture, что позволяет процессу выполнять синхронные или асинхронные операции после завершения.
Распечатайте PID процесса после его завершения:
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class ProcessDemo
{
public static void main(String[] args)
throws ExecutionException, InterruptedException, IOException
{
Process p = new ProcessBuilder("notepad.exe").start();
ProcessHandle ph = p.toHandle();
CompletableFuture<ProcessHandle> onExit = ph.onExit();
onExit.get();
onExit.thenAccept(ph_ -> System.out.printf("PID %d terminated%n", ph_.getPid()));
}
}
Метод main() сначала создает процесс notepad.exe. Впоследствии получается дескриптор процесса, и с этим дескриптором получается CompletableFuture. onExit.get() выполнит некоторые операции после того, как main() получит сигнал завершения процесса.
PID 7460 terminated
6. Заключение
Улучшения Process API в Java 9 давно назрели и приветствуются в Java. Хотя в этой статье представлены некоторые из его API, вам нужно изучить больше, например, использование метода supportsNormalTermination() или parent() и т. д.