Wenn wir Methoden in anderen Klassen in Java ausführen, unabhängig davon, ob es sich um statische oder dynamische Aufrufe handelt, werden sie im aktuellen Prozess ausgeführt, dh nur eine Java -Virtual Machine -Instanz. Manchmal müssen wir mehrere Java -Subprozesse über Java -Code starten. Obwohl dies einige Systemressourcen erfolgt, wird das Programm stabiler, da das neu gestartete Programm in verschiedenen virtuellen Maschinenprozessen ausgeführt wird.
In Java können wir zwei Methoden verwenden, um diese Anforderung zu erreichen. Der einfachste Weg ist es, die Java -Klassenname über die Exec -Methode in der Laufzeit auszuführen. Wenn die Ausführung erfolgreich ist, gibt diese Methode ein Prozessobjekt zurück. Schauen wir uns ein einfaches Beispiel unten an.
// test1.java Datei import java.io.*; Public class test {public static void main (String [] args) {FileOutputStream fout = new FileOutputStream ("C: // test1 .txt"); fout.close () ; System.out.println ("erfolgreich aufgerufen!");}} // test_exec.javapublic class test_exec {public static void main (String [] args) {runTime run = runTime.ge truntime (); prozess p = run. exec ("java test1");}}Nachdem ich das Programm über Java test_exec ausgeführt hatte, stellte ich fest, dass es eine zusätzliche Test1.TXT -Datei auf dem C -Laufwerk gab, aber die Ausgabeinformationen "erfolgreich" aufzurufen! Daher kann der Schluss gezogen werden, dass der Test erfolgreich durchgeführt wurde, aber aus irgendeinem Grund wird die Ausgangsinformationen des Tests in der Konsole von test_exec nicht ausgegeben. Dieser Grund ist auch sehr einfach, da der untergeordnete Prozess von test_exec mit Exec erstellt wird.
Wenn Sie die Ausgabeinformationen des untergeordneten Prozesses ausgeben möchten, können Sie den Ausgangsstrom des untergeordneten Prozesss durch GetInputStream im Prozess (Ausgabe im untergeordneten Prozess, Eingabe in den übergeordneten Prozess) erhalten und dann den Ausgangsstrom des Kindes übertragen Prozess aus der Konsolenausgabe des übergeordneten Prozesses. Der spezifische Implementierungscode lautet wie folgt:
// test_exec_out.javaimport java.io.*; Public class test_exec_out {public static void main (String [] args) {runTime run = runTime.getRuntime (); prozess p = run.exec ("java test1"); bufferedInputstream in = neuer BufferedInputStream (p.getInputStream ()); BufferedReader BR = New BufferedReader (neuer InputStreamReader (in)); String S; while (s = br.readline ()! = null) system.out.println (s) ;}}
Wie aus dem obigen Code ersichtlich ist, wird in test_exec_out.java die Ausgabeinformationen des untergeordneten Prozesss nach Zeile gelesen und dann wird die Ausgabe in jeder Zeile in test_exec_out durchgeführt. In der obigen Diskussion wird die Ausgabeinformationen des Kinderprozesses erhalten. Zusätzlich zu Ausgabeinformationen gibt es auch Eingabeinformationen. Da der Kinderprozess keine eigene Konsole hat, müssen auch die Eingabeinformationen vom übergeordneten Prozess bereitgestellt werden. Wir können Eingabeinformationen zum untergeordneten Prozess über die GetOutputStream -Verfahrensmethode bereitstellen (dh Eingabeinformationen vom übergeordneten Prozess zum untergeordneten Prozess, anstatt Informationen aus der Konsole einzugeben). Wir können den folgenden Code ansehen:
// test2.java Datei import java.io.*; Public class test {public static void main (string [] args) {bufferedReader bR = new bufferedReader (New InputStreamRead ER (System.in)); System.out.println ( "Informationen, die vom übergeordneten Prozess eingegeben wurden:" + br.readline ());}} // test_exec_in.javaimport java.io. .GetRuntime (); prozess p = run.exec ("Java test2"); BufferedWriter bw = neuer BufferedWriter (neuer OutputStreamWriter (P.GetOutputStream ())); BW.Write ("Ausgabe an Kinderprozessinformationen"); BW. flush (); bw.close (); Aus dem obigen Code können wir sehen, dass Test1 die Informationen erhalten, die von test_exec_in gesendet werden und diese ausgeben. Wenn Sie nicht bw.flash () und bw.close () hinzufügen, erreichen die Informationen nicht den Kinderprozess, was bedeutet, dass der Kinderprozess in einen Blockierstatus eingeht. Da der übergeordnete Prozess beendet ist, beendet sich der Kinderprozess auch aus . Wenn Sie dies beweisen möchten, können Sie system.in.read () am Ende hinzufügen und dann den Java -Prozess über den Task -Manager (unter Windows) anzeigen, und Sie werden feststellen .CLOSE (), es gibt nur ein Java -Prozess, wenn sie entfernt werden, gibt es zwei Java -Prozesse. Dies liegt daran, dass Test2 nach Erhalt der Informationen nach Erhalt der Informationen an test2 übergeben wird. Hier ist eine Sache zu erklären, dass die Ausführung von Exec asynchron ist und nicht aufhört, den folgenden Code auszuführen, da ein bestimmtes Programm blockiert wird. Daher kann nach dem Ausführen von Test2 der folgende Code weiterhin ausgeführt werden.
Die EXEC -Methode wurde viele Male neu geladen. Was oben verwendet wird, ist nur eine Überladung davon. Es kann auch Befehle und Parameter trennen, wie z. EXEC kann auch Java -virtuelle Maschinen mit unterschiedlichen Konfigurationen über bestimmte Umgebungsvariablen ausführen.
Neben der EXEC -Methode von Runtime zum Erstellen eines untergeordneten Prozesss können Sie auch einen Kinderprozess über ProcessBuilder erstellen. Die Verwendung von ProcessBuilder ist wie folgt:
// test_exec_out.javaimport java.io.*; Public class test_exec_out {public static void main (String [] args) {processBuilder pb = new ProcessBui lder ("java", "test1"); prozess pb.start () ;Bei der Errichtung von untergeordneten Prozessen ähnelt ProcessBuilder der Laufzeit. Nach dem Erhalten des Prozesses sind ihre Operationen genau gleich.
Wie bei Laufzeit kann ProcessBuilder auch die Umgebungsinformationen, das Arbeitsverzeichnis usw. der ausführbaren Datei festlegen. Im folgenden Beispiel wird beschrieben, wie diese Informationen mit ProcessBuilder festgelegt werden.
ProcessBuilder pb = new ProcessBuilder ("Befehl", "arg2", "arg2", '' '); // Umgebungsvariable Karte <String, String> env = pb.environment (); env.put ("key1", ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::: "VALUE1"); env.remove ("key2"); Env.put ("key2", env .get ("key1") + "_test"); pb.directory ("../ ABCD"); Prozessblockierungsproblem
Prozesse, die durch den Prozess dargestellt werden, funktionieren in einigen Plattformen manchmal nicht gut, insbesondere wenn sie auf Standard -Eingangsströmen arbeiten, die Ausgabe von Streams und Fehlerausgängen, die Prozesse darstellen.
Wenn die Anweisung im obigen Beispiel, die Informationen aus der Standardausgabe unterrichtet, so geändert wird, dass sie aus dem Fehlerausgangsstream gelesen werden:
stdout = new bufferedReader (neuer InputStreamReader (P.GetErrorStream ()));
Dann blockiert das Programm und kann nicht ausgeführt werden, aber dort hängen.
Wenn der Prozess beginnt, werden der Standardausgabestream und der Fehlerausgangsstrom eingeschaltet, um die Ausgabe vorzubereiten, und wenn der Prozess endet, werden sie geschlossen. Im obigen Beispiel enthält der Fehlerausgangsstrom keine Daten, die ausgegeben werden sollen, und der Standardausgabestrom hat Datenausgabe. Da die Daten im Standardausgangsstrom nicht gelesen werden, endet der Prozess nicht und der Fehlerausgangsstrom wird daher nicht geschlossen. Um dieses Problem zu lösen, können Sie zuerst den Standardausgangsstrom lesen und dann den falschen Ausgangsstrom gemäß der tatsächlichen Reihenfolge der Ausgabe lesen.
In vielen Fällen kann die Ausgangssequenz jedoch nicht eindeutig bekannt sein, insbesondere wenn Standardeingaben erforderlich sind, ist die Situation komplizierter. Zu diesem Zeitpunkt können Threads verwendet werden, um die Standardausgabe, die Fehlerausgabe und die Standardeingabe separat zu verarbeiten, und der Stream oder die Daten können gemäß ihrer Geschäftslogikbeziehung gelesen werden.
Bei Problemen, die durch Standard -Ausgangsströme und fehlerhafte Ausgangsströme verursacht werden, können Sie die RecirecterrorStream () -Methode von ProcessBuilder zu diesem Zeitpunkt verwenden.
Bei Verwendung der Waitefor () -Methode des Prozesses in einem Programm, insbesondere beim Aufrufen der Waitfor () -Methode vor dem Lesen kann dies auch zu einer Blockierung führen. Sie können Thread -Methoden verwenden, um dieses Problem zu lösen, oder Sie können die Waitfor () -Methode aufrufen, nachdem Sie Daten gelesen haben, um zu warten, bis das Programm endet.
Kurz gesagt, ich stelle hier die Verwendung der ProcessBuilder -Klasse ein, wobei die RedirecterrorStream -Methode zum Kombinieren des Standardausgangsstroms und des Fehlerausgangsstroms zu einem zuerst mit der Methode start () die Daten aus der Standardausgabe zuerst lesen. , und rufen Sie dann die Waitfor () -Methode an, um auf das Ende des Vorgangs zu warten.
wie:
java.io.buffedReader; {try {list <string> list = new ArrayList <String> (); add ("cmd.exe"); ) // die Fehlerausgabe mit dem Standardausgang PB.RecterrorStream (True); ((line = stdout.readline ())! = null) {System.out.println (Line); stdou t .CLOSE ();