Guia da API java.lang.Process

Guia da API java.lang.Process

1. Introdução

Neste tutorial, vamos pegaran in-depth look at the Process API.

Para uma visão mais superficial de como usarProcess para executar um comando shell, podemos consultar nosso tutorial anteriorhere.

O processo ao qual ele se refere é um aplicativo em execução. A classeProcess fornece métodos para interagir com esses processos, incluindo extração de saída, execução de entrada, monitoramento do ciclo de vida, verificação do status de saída e destruição (eliminação).

2. Usando a classeProcess para compilar e executar o programa Java

Vamos ver um exemplo para compilar e executar outro programa Java com a ajuda da APIProcess:

@Test
public void whenExecutedFromAnotherProgram_thenSourceProgramOutput3() throws IOException {

    Process process = Runtime.getRuntime()
      .exec("javac -cp src src\\main\\java\\com\\example\\java9\\process\\OutputStreamExample.java");
    process = Runtime.getRuntime()
      .exec("java -cp src/main/java com.example.java9.process.OutputStreamExample");
    BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));
    int value = Integer.parseInt(output.readLine());

    assertEquals(3, value);
}

Portanto, os aplicativos de execução de código Java em um código Java existente são praticamente ilimitados.

3. Processo de Criação

Nosso aplicativo Java pode recorrer a qualquer aplicativo que esteja sendo executado em nosso sistema de computador, sujeito às restrições do sistema operacional.

Portanto, podemos executar aplicativos. Vamos ver quais são os diferentes casos de uso que podemos executar utilizando a API de processo.

A classeProcessBuilder nos permite criar subprocessos dentro de nosso aplicativo.

Vamos ver uma demonstração de como abrir o aplicativo Notepad baseado no Windows:

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

4. Processo de Destruição

Process também nos fornece métodos para destruir subprocessos ou processos. Although, how the application is killed is platform-dependent.

Vamos ver os diferentes casos de uso possíveis.

4.1. Destruindo um Processo por Referência

Digamos que estejamos usando o sistema operacional Windows e queiramos gerar o aplicativo Bloco de notas e destruí-lo.

Como antes, podemos criar uma instância do aplicativo Notepad usando a classeProcessBuildere o métodostart().

Então, podemos chamar o métododestroy() em nosso objetoProcess.

4.2. Destruindo um Processo por ID

Também podemos matar processos em execução em nosso sistema operacional que talvez não sejam criados por nosso aplicativo.

Caution should be advised while doing this, as we can unknowingly destroy a critical process which might make the operating system unstable.

Primeiro, precisamos descobrir o ID do processo em execução atual, verificando o gerenciador de tarefas e descobrindo o pid.

Vamos ver um exemplo:

Optional optionalProcessHandle = ProcessHandle.of(5232);
optionalProcessHandle.ifPresent(processHandle -> processHandle.destroy());

4.3. Destruindo um Processo pela Força

Na execução do métododestroy(), o subprocesso será eliminado como vimos anteriormente neste artigo.

No caso dedestroy() não funcionar, temos a opção dedestroyForcibly().

Devemos sempre começar com o métododestroy() primeiro. Depois disso, podemos realizar uma verificação rápida no subprocesso executandoisAlive().

Se retornar verdadeiro, executedestroyForcibly():

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

5. Esperando a conclusão de um processo

Também temos dois métodos sobrecarregados, pelos quais podemos garantir que podemos aguardar a conclusão de um processo.

5.1. waitfor()

Quando este método for executado, ele colocaráthe current execution process thread in a blocking-wait state unless the sub-process gets terminated.

Vejamos o exemplo:

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

Podemos ver no exemplo acima que o encadeamento atual continuará a execução e continuará aguardando o término do encadeamento do subprocesso. Quando o subprocesso terminar, o encadeamento atual continuará sua execução.

5.2. waitfor(long timeOut, TimeUnit time)

Quando este método for executado, ele colocaráthe current execution process thread in the blocking-wait state unless the sub-process gets terminated or runs out of time.

Vejamos o exemplo:

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

Podemos ver no exemplo acima que o encadeamento atual continuará a execução e continuará aguardando o término do encadeamento do subprocesso ou se o intervalo de tempo especificado expirou.

Quando esse método é executado, ele retornará um valor booleano true se o subprocesso foi encerrado ou um valor booleano false se o tempo de espera tiver decorrido antes da saída do subprocesso.

6. exitValue()

Quando este método é executado, o thread atual não espera que o subprocesso seja encerrado ou destruído, no entanto, ele lançará umIllegalThreadStateException se o subprocesso não for encerrado.

Another way around if the subprocess has been successfully terminated then it will result in an exit value of the process.

Pode ser qualquer número inteiro positivo possível.

Vejamos um exemplo em que o métodoexitValue() retorna um número inteiro positivo quando o subprocesso foi encerrado com sucesso:

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

7. isAlive()

Quando gostaríamos de realizar o processamento de negócios, que é subjetivo, quer o processo esteja ativo ou não.

Podemos realizar uma verificação rápida para descobrir se o processo está ativo ou não, que retorna um valor booleano.

Vamos ver um exemplo rápido disso:

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

8. Manipulando fluxos de processo

Por padrão, o subprocesso criado não possui seu terminal ou console. Todas as suas operações de E / S padrão (ou seja, stdin, stdout, stderr) serão enviadas ao processo pai. Dessa forma, o processo pai pode usar esses fluxos para alimentar a entrada e obter a saída do subprocesso.

Conseqüentemente, isso nos dá uma enorme flexibilidade, pois nos dá controle sobre a entrada / saída de nosso subprocesso.

8.1. getErrorStream()

Curiosamente, podemos buscar os erros gerados a partir do subprocesso e realizar o processamento comercial.

Depois disso, podemos executar verificações específicas de processamento de negócios com base em nossos requisitos.

Vamos ver um exemplo:

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

8.2. getInputStream()

Também podemos buscar a saída gerada por um subprocesso e consumir dentro do processo pai, permitindo assim compartilhar informações entre os processos:

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

    assertEquals(3, value);
}

8.3. getOutputStream()

Podemos enviar entrada para um subprocesso a partir de um processo pai:

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

8.4. Filtrar fluxos de processo

É um caso de uso perfeitamente válido para interagir com processos seletivos em execução.

Process nos fornece a facilidade de filtrar seletivamente os processos em execução com base em um determinado predicado.

Depois disso, podemos executar operações de negócios nesse conjunto de processos seletivos:

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

9. Conclusão

Process é uma classe poderosa para interação em nível de sistema operacional. Acionando comandos do terminal, bem como iniciando, monitorando e eliminando aplicativos.

Para obter mais informações sobre a API Java 9 Process, dê uma olhada em nosso artigohere.

Como sempre, você encontrará as fontesover on Github.