Рубрики
Без рубрики

Руководство по java.lang.API процесса

Краткое и практическое руководство по API процессов Java.

Автор оригинала: baeldung.

1. введение

В этом уроке мы подробно рассмотрим Процесс API .

Для более поверхностного изучения того, как использовать Process для выполнения команды оболочки, мы можем обратиться к нашему предыдущему учебнику здесь .

Процесс, на который он ссылается, является выполняемым приложением. Класс Process предоставляет методы для взаимодействия с этими процессами, включая извлечение выходных данных, выполнение ввода, мониторинг жизненного цикла, проверку состояния выхода и его уничтожение (уничтожение).

2. Использование класса Process для компиляции и запуска Java-программы

Давайте рассмотрим пример компиляции и запуска другой программы Java с помощью Process API:

@Test
public void whenExecutedFromAnotherProgram_thenSourceProgramOutput3() throws IOException {
 
    Process process = Runtime.getRuntime()
      .exec("javac -cp src src\\main\\java\\com\\baeldung\\java9\\process\\OutputStreamExample.java");
    process = Runtime.getRuntime() 
      .exec("java -cp src/main/java com.baeldung.java9.process.OutputStreamExample");
    BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));
    int value = Integer.parseInt(output.readLine());
 
    assertEquals(3, value);
}

Таким образом, возможности выполнения Java-кода в рамках существующего Java-кода практически безграничны.

3. Процесс Создания

Наше Java – приложение может вызывать любое приложение, работающее в нашей компьютерной системе, в соответствии с ограничениями операционной системы.

Поэтому мы можем выполнять заявки. Давайте посмотрим, каковы различные варианты использования, которые мы можем запустить, используя API процесса.

Класс ProcessBuilder позволяет нам создавать подпроцессы в нашем приложении.

Давайте посмотрим демонстрацию открытия приложения Блокнота на базе Windows:

ProcessBuilder builder = new ProcessBuilder("notepad.exe");
Process process = builder.start();

4. Процесс Разрушения

Процесс также предоставляет нам методы для уничтожения подпроцессов или процессов. Хотя способ уничтожения приложения зависит от платформы .

Давайте рассмотрим различные варианты использования, которые возможны.

4.1. Уничтожение процесса по ссылке

Допустим, мы используем ОС Windows и хотим создать приложение Блокнота и уничтожить его.

Как и прежде, мы можем создать экземпляр приложения Notepad с помощью класса ProcessBuilder и метода start () .

Затем мы можем вызвать метод destroy() для нашего объекта Process .

4.2. Уничтожение процесса по идентификатору

Мы также можем убивать процессы, запущенные в нашей операционной системе, которые не могут быть созданы нашим приложением.

При этом следует соблюдать осторожность, так как мы можем неосознанно уничтожить критический процесс, который может сделать операционную систему нестабильной .

Сначала нам нужно узнать идентификатор процесса текущего запущенного процесса, проверив диспетчер задач и выяснив pid.

Давайте рассмотрим пример:

long pid = /* PID to kill */;
Optional optionalProcessHandle = ProcessHandle.of(pid);
optionalProcessHandle.ifPresent(processHandle -> processHandle.destroy());

4.3. Разрушение процесса силой

При выполнении метода destroy() подпроцесс будет уничтожен, как мы видели ранее в этой статье.

В случае, когда уничтожать() не работает, у нас есть возможность Разрушительно() .

Мы всегда должны начинать с метода destroy () . После этого мы можем выполнить быструю проверку подпроцесса, выполнив IsAlive() .

Если он возвращает true, то выполните destroyForcibly() :

ProcessBuilder builder = new ProcessBuilder("notepad.exe");
Process process = builder.start();
process.destroy();
if (process.isAlive()) {
    process.destroyForcibly();
}

5. Ожидание завершения процесса

У нас также есть два перегруженных метода, с помощью которых мы можем гарантировать, что сможем дождаться завершения процесса.

5.1. подождите()

Когда этот метод выполняется, он помещает текущий поток процесса выполнения в состояние ожидания блокировки, если подпроцесс не будет завершен .

Давайте рассмотрим пример:

ProcessBuilder builder = new ProcessBuilder("notepad.exe");
Process process = builder.start();
assertThat(process.waitFor() >= 0);

Из приведенного выше примера видно, что для продолжения выполнения текущего потока он будет продолжать ждать завершения потока подпроцесса. Как только подпроцесс завершится, текущий поток продолжит свое выполнение.

5.2. waitfor(длительный тайм-аут, время ожидания)

Когда этот метод выполняется, он помещает текущий поток процесса выполнения в состояние ожидания блокировки, если только подпроцесс не будет завершен или не закончится время .

Давайте рассмотрим пример:

ProcessBuilder builder = new ProcessBuilder("notepad.exe");
Process process = builder.start();
assertFalse(process.waitFor(1, TimeUnit.SECONDS));

Из приведенного выше примера видно, что для продолжения выполнения текущего потока он будет продолжать ждать завершения потока подпроцесса или истечения указанного интервала времени.

Когда этот метод выполняется, он возвращает логическое значение true, если подпроцесс вышел, или логическое значение false, если время ожидания истекло до выхода подпроцесса.

6. Значение выхода()

При запуске этого метода текущий поток не будет ждать завершения или уничтожения подпроцесса, однако он вызовет исключение IllegalThreadStateException , если подпроцесс не будет завершен.

По – другому, если подпроцесс был успешно завершен, это приведет к значению выхода процесса .

Это может быть любое возможное положительное целое число.

Давайте рассмотрим пример, когда метод exitValue() возвращает положительное целое число, когда подпроцесс был успешно завершен:

@Test
public void 
  givenSubProcess_whenCurrentThreadWillNotWaitIndefinitelyforSubProcessToEnd_thenProcessExitValueReturnsGrt0() 
  throws IOException {
    ProcessBuilder builder = new ProcessBuilder("notepad.exe");
    Process process = builder.start();
    assertThat(process.exitValue() >= 0);
}

7. IsAlive()

Когда мы хотим выполнить бизнес-обработку, которая является субъективной, независимо от того, является ли процесс живым или нет.

Мы можем выполнить быструю проверку, чтобы определить, является ли процесс живым или нет, который возвращает логическое значение.

Давайте рассмотрим краткий пример этого:

ProcessBuilder builder = new ProcessBuilder("notepad.exe");
Process process = builder.start();
Thread.sleep(10000);
process.destroy();
assertTrue(process.isAlive());

8. Обработка потоков процессов

По умолчанию созданный подпроцесс не имеет своего терминала или консоли. Все его стандартные операции ввода-вывода (например, stdin, stdout, stderr) будут отправлены родительскому процессу. Таким образом, родительский процесс может использовать эти потоки для подачи входных данных в подпроцесс и получения выходных данных из него.

Следовательно, это дает нам огромную гибкость, поскольку дает нам контроль над вводом/выводом нашего подпроцесса.

8.1. getErrorStream()

Интересно, что мы можем извлечь ошибки, сгенерированные из подпроцесса, и затем выполнить бизнес-обработку.

После этого мы можем выполнить конкретные проверки бизнес-обработки в соответствии с нашими требованиями.

Давайте рассмотрим пример:

@Test
public void givenSubProcess_whenEncounterError_thenErrorStreamNotNull() throws IOException {
    Process process = Runtime.getRuntime().exec(
      "javac -cp src src\\main\\java\\com\\baeldung\\java9\\process\\ProcessCompilationError.java");
    BufferedReader error = new BufferedReader(new InputStreamReader(process.getErrorStream()));
    String errorString = error.readLine();
    assertNotNull(errorString);
}

8.2. getInputStream()

Мы также можем извлекать выходные данные, генерируемые подпроцессом, и потреблять их в родительском процессе, что позволяет обмениваться информацией между процессами:

@Test
public void givenSourceProgram_whenReadingInputStream_thenFirstLineEquals3() throws IOException {
    Process process = Runtime.getRuntime().exec(
      "javac -cp src src\\main\\java\\com\\baeldung\\java9\\process\\OutputStreamExample.java");
    process = Runtime.getRuntime()
      .exec("java -cp  src/main/java com.baeldung.java9.process.OutputStreamExample");
    BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));
    int value = Integer.parseInt(output.readLine());
 
    assertEquals(3, value);
}

8.3. getOutputStream()

Мы можем отправлять входные данные в подпроцесс из родительского процесса:

Writer w = new OutputStreamWriter(process.getOutputStream(), "UTF-8");
w.write("send to child\n");

8.4. Фильтрация технологических потоков

Это вполне допустимый вариант использования для взаимодействия с выборочными запущенными процессами.

Process предоставляет нам возможность выборочно фильтровать запущенные процессы на основе определенного предиката.

После этого мы можем выполнять бизнес-операции с этим набором выборочных процессов:

@Test
public void givenRunningProcesses_whenFilterOnProcessIdRange_thenGetSelectedProcessPid() {
    assertThat(((int) ProcessHandle.allProcesses()
      .filter(ph -> (ph.pid() > 10000 && ph.pid() < 50000))
      .count()) > 0);
}

9. Заключение

Process – это мощный класс для взаимодействия на уровне операционной системы. Запуск команд терминала, а также запуск, мониторинг и уничтожение приложений.

Для получения дополнительной информации об API процессов Java 9 ознакомьтесь с нашей статьей здесь .

Как всегда, вы найдете источники на Github .