Guía de la API java.lang.Process

1. Introducción

En este tutorial, analizaremos en profundidad la API de proceso .

Para una mirada más superficial sobre cómo usar Process para ejecutar un comando de shell, podemos consultar nuestro tutorial anterior aquí.

El proceso al que se refiere es una aplicación en ejecución. La clase Process proporciona métodos para interactuar con estos procesos, incluida la extracción de resultados, la realización de entradas, la supervisión del ciclo de vida, la comprobación del estado de salida y su destrucción (eliminación).

2. Uso de la clase de proceso para compilar y ejecutar un programa Java

Veamos un ejemplo para compilar y ejecutar otro programa Java con la ayuda de 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); }

Por lo tanto, las aplicaciones para ejecutar código Java dentro de un código Java existente son prácticamente ilimitadas.

3. Proceso de creación

Nuestra aplicación Java puede recurrir a cualquier aplicación que se ejecute dentro de nuestro sistema informático sujeto a las restricciones del sistema operativo.

Por tanto, podemos ejecutar aplicaciones. Veamos cuáles son los diferentes casos de uso que podemos ejecutar utilizando la API de proceso.

La clase ProcessBuilder nos permite crear subprocesos dentro de nuestra aplicación.

Veamos una demostración de cómo abrir la aplicación Bloc de notas basada en Windows:

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

4. Proceso de destrucción

El proceso también nos proporciona métodos para destruir subprocesos o procesos. Aunque, la forma en que se elimina la aplicación depende de la plataforma .

Veamos diferentes casos de uso por los que son posibles.

4.1. Destrucción de un proceso por referencia

Digamos que estamos usando el sistema operativo Windows y queremos generar la aplicación Bloc de notas y destruirla.

Como antes, podemos crear una instancia de la aplicación Bloc de notas utilizando la clase ProcessBuilder y el método start () .

Entonces podemos llamar al método destroy () en nuestro objeto Process .

4.2. Destrucción de un proceso por ID

También podemos matar procesos que se están ejecutando dentro de nuestro sistema operativo y que pueden no ser creados por nuestra aplicación.

Se debe tener precaución al hacer esto, ya que, sin saberlo, podemos destruir un proceso crítico que podría hacer que el sistema operativo sea inestable .

Primero necesitamos averiguar el ID de proceso del proceso en ejecución actual comprobando el administrador de tareas y averiguando el pid.

Veamos un ejemplo:

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

4.3. Destruir un proceso por la fuerza

En la ejecución del método destroy () , el subproceso se eliminará como vimos anteriormente en el artículo.

En el caso de que destroy () no funcione, tenemos la opción de destroyForcibly () .

Siempre debemos comenzar primero con el método destroy () . Después de eso, podemos realizar una comprobación rápida del subproceso ejecutando isAlive () .

Si devuelve verdadero, ejecute destroyForcbly () :

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

5. Esperando a que se complete un proceso

También tenemos dos métodos sobrecargados, a través de los cuales podemos asegurarnos de que podemos esperar a que se complete un proceso.

5.1. esperar ()

Cuando se ejecuta este método, colocará el subproceso del proceso de ejecución actual en un estado de espera de bloqueo a menos que se termine el subproceso .

Echemos un vistazo al ejemplo:

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

Podemos ver en el ejemplo anterior que el hilo actual para continuar la ejecución seguirá esperando a que finalice el hilo del subproceso. Una vez que finaliza el subproceso, el hilo actual continuará su ejecución.

5.2. waitfor (long timeOut, TimeUnit time)

Cuando se ejecuta este método, colocará el subproceso del proceso de ejecución actual en el estado de espera de bloqueo a menos que el subproceso se termine o se agote el tiempo .

Echemos un vistazo al ejemplo:

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

Podemos ver en el ejemplo anterior que el hilo actual para continuar la ejecución seguirá esperando a que finalice el subproceso o si ha transcurrido el intervalo de tiempo especificado.

Cuando se ejecuta este método, devolverá un valor booleano verdadero si el subproceso ha salido o un valor booleano falso si el tiempo de espera había transcurrido antes de que el subproceso saliera.

6. exitValue ()

When this method is run then the current thread won't wait for the sub-process to get terminated or destroyed, however, it will throw an IllegalThreadStateException if the subprocess isn't terminated.

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

It can be any possible positive integer number.

Let's look at an example when the exitValue() method returns a positive integer when the subprocess has been terminated successfully:

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

7. isAlive()

When we'd like to perform business processing which is subjective whether the process is alive or not.

We can perform a quick check to find whether the process is alive or not which returns a boolean value.

Let's see a quick example of it:

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

8. Handling Process Streams

By default, the created subprocess does not have its terminal or console. All its standard I/O (i.e., stdin, stdout, stderr) operations will be sent to the parent process. Thereby the parent process can use these streams to feed input to and get output from the subprocess.

Consequently, this gives us a huge amount of flexibility as it gives us control over the input/output of our sub-process.

8.1. getErrorStream()

Interestingly we can fetch the errors generated from the subprocess and thereon perform business processing.

After that, we can execute specific business processing checks based on our requirements.

Let's see an example:

@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()

We can also fetch the output generated by a subprocess and consume within the parent process thus allowing share information between the processes:

@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()

We can send input to a subprocess from a parent process:

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

8.4. Filter Process Streams

It's a perfectly valid use-case to interact with selective running processes.

Process provides us the facility to selectively filter running processes based on a certain predicate.

After that we can perform business operations on this selective process set:

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

9. Conclusion

Process is a powerful class for Operating System level interaction. Triggering terminal commands as well as launching, monitoring and killing applications.

For more reading on the Java 9 Process API, take a look at our article here.

Como siempre, encontrarás las fuentes en Github.