Anleitung zur API java.lang.Process

Anleitung zur java.lang.Process API

1. Einführung

In diesem Tutorial nehmen wiran in-depth look at the Process API.

Für einen flacheren Blick auf die Verwendung vonProcess zum Ausführen eines Shell-Befehls verweisen wir auf unser vorheriges Tutorialhere.

Der Prozess, auf den es verweist, ist eine ausführende Anwendung. Die KlasseProcess bietet Methoden für die Interaktion mit diesen Prozessen, einschließlich Extrahieren von Ausgaben, Durchführen von Eingaben, Überwachen des Lebenszyklus, Überprüfen des Beendigungsstatus und Zerstören (Beenden).

2. Verwenden derProcess-Klasse zum Kompilieren und Ausführen von Java-Programmen

Sehen wir uns ein Beispiel zum Kompilieren und Ausführen eines anderen Java-Programms mithilfe der API vonProcessan:

@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);
}

Somit sind den Anwendungen zum Ausführen von Java-Code innerhalb eines vorhandenen Java-Codes praktisch keine Grenzen gesetzt.

3. Prozess erstellen

Unsere Java-Anwendung kann alle Anwendungen aufrufen, die auf unserem Computersystem ausgeführt werden, und unterliegt den Einschränkungen des Betriebssystems.

Daher können wir Anwendungen ausführen. Lassen Sie uns sehen, welche unterschiedlichen Anwendungsfälle wir mithilfe der Prozess-API ausführen können.

Mit der KlasseProcessBuilderkönnen wir Unterprozesse in unserer Anwendung erstellen.

Sehen wir uns eine Demo zum Öffnen der Windows-basierten Notepad-Anwendung an:

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

4. Prozess zerstören

Process bietet uns auch Methoden, um Unterprozesse oder Prozesse zu zerstören. Although, how the application is killed is platform-dependent.

Sehen wir uns verschiedene Anwendungsfälle an, die möglich sind.

4.1. Zerstören eines Prozesses durch Referenz

Angenommen, wir verwenden das Windows-Betriebssystem und möchten die Notepad-Anwendung erzeugen und zerstören.

Nach wie vor können wir eine Instanz der Notepad-Anwendung mithilfe der KlasseProcessBuilderund der Methodestart()erstellen.

Dann können wir diedestroy()-Methode für unserProcess-Objekt aufrufen.

4.2. Prozess durch ID zerstören

Wir können auch Prozesse beenden, die in unserem Betriebssystem ausgeführt werden und möglicherweise nicht von unserer Anwendung erstellt wurden.

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

Wir müssen zuerst die Prozess-ID des aktuell ausgeführten Prozesses herausfinden, indem wir den Task-Manager überprüfen und die PID herausfinden.

Sehen wir uns ein Beispiel an:

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

4.3. Einen Prozess mit Gewalt zerstören

Bei der Ausführung derdestroy()-Methode wird der Unterprozess beendet, wie wir weiter oben im Artikel gesehen haben.

Für den Fall, dassdestroy() nicht funktioniert, haben wir die OptiondestroyForcibly().

Wir sollten immer zuerst mit der Methodedestroy()beginnen. Danach können wir den Unterprozess schnell überprüfen, indem wirisAlive() ausführen.

Wenn es true zurückgibt, führen SiedestroyForcibly() aus:

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

5. Warten auf den Abschluss eines Prozesses

Wir haben auch zwei überladene Methoden, mit denen wir sicherstellen können, dass wir auf den Abschluss eines Prozesses warten können.

5.1. waitfor()

Wenn diese Methode ausgeführt wird, werdenthe current execution process thread in a blocking-wait state unless the sub-process gets terminated platziert.

Schauen wir uns das Beispiel an:

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

Wir können aus dem obigen Beispiel ersehen, dass der aktuelle Thread, um mit der Ausführung fortzufahren, weiterhin auf das Ende des Subprozess-Threads wartet. Sobald der Unterprozess beendet ist, setzt der aktuelle Thread seine Ausführung fort.

5.2. waitfor(long timeOut, TimeUnit time)

Wenn diese Methode ausgeführt wird, werdenthe current execution process thread in the blocking-wait state unless the sub-process gets terminated or runs out of time platziert.

Schauen wir uns das Beispiel an:

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

Um die Ausführung des aktuellen Threads fortzusetzen, können Sie dem obigen Beispiel entnehmen, dass er weiterhin auf das Ende des Subprozess-Threads wartet oder ob das angegebene Zeitintervall abgelaufen ist.

Wenn diese Methode ausgeführt wird, gibt sie den Booleschen Wert true zurück, wenn der Unterprozess beendet wurde, oder den Booleschen Wert false, wenn die Wartezeit vor dem Beenden des Unterprozesses abgelaufen ist.

6. exitValue()

Wenn diese Methode ausgeführt wird, wartet der aktuelle Thread nicht darauf, dass der Unterprozess beendet oder zerstört wird. Er gibt jedochIllegalThreadStateException aus, wenn der Unterprozess nicht beendet wird.

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

Es kann sich um eine beliebige positive Ganzzahl handeln.

Schauen wir uns ein Beispiel an, in dem die MethodeexitValue()eine positive Ganzzahl zurückgibt, wenn der Unterprozess erfolgreich beendet wurde:

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

7. isAlive()

Wenn wir eine Geschäftsabwicklung durchführen möchten, ist dies subjektiv, unabhängig davon, ob der Prozess aktiv ist oder nicht.

Wir können eine schnelle Überprüfung durchführen, um festzustellen, ob der Prozess aktiv ist oder nicht, der einen booleschen Wert zurückgibt.

Sehen wir uns ein kurzes Beispiel dafür an:

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

8. Prozessströme verarbeiten

Standardmäßig verfügt der erstellte Unterprozess nicht über ein Terminal oder eine Konsole. Alle Standard-E / A-Operationen (d. H. Stdin, stdout, stderr) werden an den übergeordneten Prozess gesendet. Dadurch kann der übergeordnete Prozess diese Streams verwenden, um dem Unterprozess Eingaben zuzuführen und Ausgaben daraus zu erhalten.

Dies gibt uns eine enorme Flexibilität, da wir die Kontrolle über die Eingabe / Ausgabe unseres Unterprozesses haben.

8.1. getErrorStream()

Interessanterweise können wir die aus dem Teilprozess generierten Fehler abrufen und daraufhin die Geschäftsabwicklung durchführen.

Danach können wir auf der Grundlage unserer Anforderungen spezifische Geschäftsprozessprüfungen durchführen.

Sehen wir uns ein Beispiel an:

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

Wir können auch die von einem Unterprozess generierte Ausgabe abrufen und innerhalb des übergeordneten Prozesses verarbeiten, sodass Informationen zwischen den Prozessen ausgetauscht werden können:

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

Wir können Eingaben von einem übergeordneten Prozess an einen Unterprozess senden:

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

8.4. Prozessströme filtern

Dies ist ein absolut gültiger Anwendungsfall für die Interaktion mit selektiv ausgeführten Prozessen.

Process bietet uns die Möglichkeit, laufende Prozesse basierend auf einem bestimmten Prädikat selektiv zu filtern.

Danach können wir mit diesem selektiven Prozesssatz Geschäftsvorgänge ausführen:

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

9. Fazit

Process ist eine leistungsstarke Klasse für die Interaktion auf Betriebssystemebene. Auslösen von Terminalbefehlen sowie Starten, Überwachen und Beenden von Anwendungen.

Weitere Informationen zur Java 9-Prozess-API finden Sie in unserem Artikelhere.

Wie immer finden Sie die Quellenover on Github.