Guide de l’API java.lang.Process

Guide de l'API java.lang.Process

1. introduction

Dans ce didacticiel, nous allons prendrean in-depth look at the Process API.

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

Le processus auquel il fait référence est une application en cours d'exécution. La classeProcess 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 classeProcess 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 l’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);
}

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

3. Processus de création

Notre application Java peut faire appel à toutes les applications fonctionnant dans notre système, en fonction des restrictions imposées par le 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 classeProcessBuilder nous permet de créer des sous-processus dans notre application.

Voyons une démonstration de l’ouverture de l’application Bloc-notes 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. Although, how the application is killed is platform-dependent.

Voyons différents cas d’utilisation possibles.

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

Supposons que nous utilisions le système d'exploitation Windows et que nous souhaitions 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 classeProcessBuilder et la méthodestart().

Ensuite, nous pouvons appeler la méthodedestroy() sur notre objetProcess.

4.2. Détruire un processus par ID

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

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

Nous devons d’abord connaître l’identifiant du processus en cours en vérifiant le gestionnaire de tâches et connaître 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éthodedestroy(), le sous-processus sera tué comme nous l'avons vu plus haut dans l'article.

Dans le cas oùdestroy() ne fonctionne pas, nous avons l’option dedestroyForcibly().

Nous devrions toujours commencer par la méthodedestroy() en premier. Après cela, nous pouvons effectuer une vérification rapide sur le sous-processus en exécutantisAlive().

Si elle renvoie true, exécutezdestroyForcibly():

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 d’attendre la fin d’un processus.

5.1. waitfor()

Lorsque cette méthode est exécutée, elle placethe current execution process thread in a blocking-wait state unless the sub-process gets terminated.

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 l'exécution, il attend toujours que le thread de sous-processus se termine. Une fois le sous-processus terminé, le thread actuel poursuivra son exécution.

5.2. waitfor(long timeOut, TimeUnit time)

Lorsque cette méthode est exécutée, elle placethe current execution process thread in the blocking-wait state unless the sub-process gets terminated or runs out of time.

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 en cours continue l'exécution, il attend toujours que le thread de sous-processus se termine ou que l'intervalle de temps spécifié se soit écoulé.

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

6. exitValue()

Lorsque cette méthode est exécutée, le thread actuel n’attend pas que le sous-processus soit terminé ou détruit, cependant, il lancera unIllegalThreadStateException si le sous-processus n’est pas terminé.

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

Il peut s'agir de tout nombre entier positif possible.

Regardons un exemple lorsque la méthodeexitValue() renvoie un entier positif lorsque le sous-processus s'est terminé avec succès:

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

7. isAlive()

Lorsque nous souhaitons effectuer un traitement commercial qui est subjectif, que le processus soit actif ou non.

Nous pouvons effectuer une vérification rapide pour déterminer si le processus est actif ou non, ce qui renvoie une valeur booléenne.

Voyons un petit exemple:

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

8. Gestion des flux de processus

Par défaut, le sous-processus créé n'a pas de terminal ni de console. Toutes ses opérations d’E / S standard (c.-à-d. Stdin, stdout, stderr) seront envoyées au processus parent. De ce fait, le processus parent peut utiliser ces flux pour alimenter le sous-processus et en obtenir la sortie.

Par conséquent, cela nous donne une énorme flexibilité car cela nous permet de contrôler les entrées / sorties de notre sous-processus.

8.1. getErrorStream()

De manière intéressante, nous pouvons récupérer les erreurs générées à partir du sous-processus et y effectuer un traitement.

Ensuite, nous pouvons exécuter des contrôles de traitement métier spécifiques en fonction de nos besoins.

Voyons un exemple:

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

Nous pouvons également extraire la sortie générée par un sous-processus et la consommer dans le processus parent, permettant ainsi de partager des informations entre les processus:

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

Nous pouvons envoyer des entrées à un sous-processus à partir d'un processus parent:

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

8.4. Filtrer les flux de processus

C’est un cas d’utilisation parfaitement valable pour interagir avec des processus d’exécution sélectifs.

Process nous offre la possibilité de filtrer sélectivement les processus en cours en fonction d'un certain prédicat.

Après cela, nous pouvons effectuer des opérations commerciales sur cet ensemble de processus sélectif:

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

9. Conclusion

Process est une classe puissante pour l'interaction au niveau du système d'exploitation. Déclenchement des commandes de terminal ainsi que lancement, surveillance et destruction d'applications.

Pour plus d'informations sur l'API Java 9 Process, consultez notre articlehere.

Comme toujours, vous trouverez les sourcesover on Github.