Anleitung zur java.lang.Process API

1. Einleitung

In diesem Tutorial werden wir uns eingehend mit der Prozess- API befassen .

Weitere Informationen zur Verwendung von Process zum Ausführen eines Shell-Befehls finden Sie in unserem vorherigen Lernprogramm.

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

2. Verwenden der Prozessklasse zum Kompilieren und Ausführen des Java-Programms

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

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

Somit sind die Anwendungen zum Ausführen von Java-Code innerhalb eines vorhandenen Java-Codes praktisch unbegrenzt.

3. Prozess erstellen

Unsere Java-Anwendung kann jede Anwendung aufrufen, die in unserem Computersystem ausgeführt wird und den Einschränkungen des Betriebssystems unterliegt.

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 ProcessBuilder- Klasse kö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. Zerstörungsprozess

Der Prozess bietet uns auch Methoden, um Unterprozesse oder Prozesse zu zerstören. Wie die Anwendung beendet wird, hängt jedoch von der Plattform ab .

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

4.1. Einen Prozess durch Referenz zerstören

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

Nach wie vor können wir mithilfe der ProcessBuilder- Klasse und der start () -Methode eine Instanz der Notepad-Anwendung erstellen .

Dann können wir die destroy () -Methode für unser Process- 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.

Vorsicht ist dabei geboten, da wir einen kritischen Prozess unwissentlich zerstören können, der das Betriebssystem instabil machen könnte .

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

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 der destroy () -Methode wird der Unterprozess beendet, wie wir weiter oben im Artikel gesehen haben.

Für den Fall, dass destroy () nicht funktioniert, haben wir die Option destroyForcibly () .

Wir sollten immer zuerst mit der Methode destroy () beginnen . Danach können wir den Unterprozess schnell überprüfen, ob durch Ausführen von isAlive () .

Wenn es true zurückgibt, führen Sie destroyForcibly () 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. warten auf()

Wenn diese Methode ausgeführt wird, wird der aktuelle Thread des Ausführungsprozesses in einen blockierenden Wartezustand versetzt, sofern der Unterprozess nicht beendet wird .

Schauen wir uns das Beispiel an:

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

Aus dem obigen Beispiel geht hervor, dass der aktuelle Thread die Ausführung fortsetzt und weiterhin auf das Ende des Unterprozess-Threads wartet. Sobald der Unterprozess beendet ist, setzt der aktuelle Thread seine Ausführung fort.

5.2. Warten auf (lange timeOut, TimeUnit Zeit)

Wenn diese Methode ausgeführt wird, wird der aktuelle Thread des Ausführungsprozesses in den Status "Blockieren-Warten" versetzt, es sei denn, der Unterprozess wird beendet oder die Zeit läuft ab .

Schauen wir uns das Beispiel an:

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

Aus dem obigen Beispiel geht hervor, dass der aktuelle Thread, um die Ausführung fortzusetzen, weiterhin darauf wartet, dass der Unterprozess-Thread beendet wird oder dass das angegebene Zeitintervall abgelaufen ist.

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

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.

Wie immer finden Sie die Quellen auf Github.