Guide de l'API java.lang.Process

1. Introduction

Dans ce didacticiel, nous allons examiner en profondeur l' API Process .

Pour un aperçu moins profond de la façon d'utiliser Process pour exécuter une commande shell, nous pouvons vous référer à notre tutoriel précédent ici.

Le processus auquel il fait référence est une application en cours d'exécution. La classe Process fournit des méthodes pour interagir avec ces processus, notamment l'extraction de la sortie, l'exécution d'une entrée, la surveillance du cycle de vie, la vérification de l'état de sortie et sa destruction (suppression).

2. Utilisation de la classe de processus pour la compilation et l'exécution du programme Java

Voyons un exemple pour compiler et exécuter un autre programme Java à l'aide 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); }

Ainsi, les applications d'exécution de code Java dans un code Java existant sont pratiquement illimitées.

3. Création du processus

Notre application Java peut faire appel à n'importe quelle application qui s'exécute dans notre système informatique en fonction des restrictions du système d'exploitation.

Par conséquent, nous pouvons exécuter des applications. Voyons quels sont les différents cas d'utilisation que nous pouvons exécuter en utilisant l'API Process.

La classe ProcessBuilder nous permet de créer des sous-processus dans notre application.

Voyons une démonstration de l'ouverture de l'application Notepad basée sur Windows:

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

4. Processus de destruction

Process nous fournit également des méthodes pour détruire les sous-processus ou processus. Cependant, la façon dont l'application est supprimée dépend de la plate-forme .

Voyons différents cas d'utilisation par lesquels sont possibles.

4.1. Détruire un processus par référence

Disons que nous utilisons le système d'exploitation Windows et que nous voulons créer l'application Notepad et la détruire.

Comme précédemment, nous pouvons créer une instance de l'application Notepad en utilisant la classe ProcessBuilder et la méthode start () .

Ensuite, nous pouvons appeler la méthode destroy () sur notre objet Process .

4.2. Détruire un processus par ID

Nous pouvons également tuer les processus en cours d'exécution dans notre système d'exploitation qui pourraient ne pas être créés par notre application.

Il faut être prudent en faisant cela, car nous pouvons détruire sans le savoir un processus critique qui pourrait rendre le système d'exploitation instable .

Nous devons d'abord trouver l'ID de processus du processus en cours d'exécution en vérifiant le gestionnaire de tâches et trouver le pid.

Voyons un exemple:

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

4.3. Détruire un processus par la force

Lors de l'exécution de la méthode destroy () , le sous-processus sera tué comme nous l'avons vu précédemment dans l'article.

Dans le cas où destroy () ne fonctionne pas, nous avons la possibilité de destroyForcably () .

Nous devrions toujours commencer par la méthode destroy () en premier. Après cela, nous pouvons effectuer une vérification rapide du sous-processus en exécutant isAlive () .

Si elle renvoie true, exécutez destroyForcably () :

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

5. En attente de la fin d'un processus

Nous avons également deux méthodes surchargées, grâce auxquelles nous pouvons nous assurer que nous pouvons attendre la fin d'un processus.

5.1. attendre()

Lorsque cette méthode est exécutée, elle place le thread du processus d'exécution actuel dans un état d'attente de blocage à moins que le sous-processus ne soit arrêté .

Jetons un œil à l'exemple:

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

Nous pouvons voir dans l'exemple ci-dessus que le thread actuel continue son exécution, il continuera d'attendre la fin du thread de sous-processus. Une fois le sous-processus terminé, le thread actuel continuera son exécution.

5.2. waitfor (long timeOut, heure TimeUnit)

Lorsque cette méthode est exécutée, elle place le thread du processus d'exécution actuel dans l'état d'attente de blocage à moins que le sous-processus ne se termine ou ne manque pas de temps .

Jetons un œil à l'exemple:

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

Nous pouvons voir dans l'exemple ci-dessus que le thread actuel continue son exécution, il continuera à attendre que le thread de sous-processus se termine ou que l'intervalle de temps spécifié soit écoulé.

Lorsque cette méthode est exécutée, elle renverra une valeur booléenne true si le sous-processus est terminé ou une valeur booléenne false si le temps d'attente s'est écoulé avant la fin du sous-processus.

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.

Comme toujours, vous trouverez les sources sur Github.