一般に、Javaの他のクラスでメソッドを実行すると、静的呼び出しであろうと動的呼び出しであろうと、現在のプロセスで実行されます。つまり、実行中のJava仮想マシンインスタンスは1つだけです。時々、Javaコードを介して複数のJavaサブプロセスを開始する必要があります。これを行うと、システムのリソースが増えますが、新しく開始されたプログラムが異なる仮想マシンプロセスで実行されると、プログラムがより安定します。
Javaでは、この要件を実現するために2つの方法を使用できます。最も簡単な方法は、実行時にExecメソッドを介してJavaクラス名を実行することです。実行が成功した場合、このメソッドはプロセスオブジェクトを返します。以下の簡単な例を見てみましょう。
// test1.javaファイルインポートJava.io。 ; system.out.println( "calling callingfully!");}} // test_exec.javapublic class test_exec {public static void main(string [] args){runtime run = runtime.ge truntime(); process p = run。 exec( "Java test1");}}Java test_execを介してプログラムを実行した後、Cドライブに追加のtest1.txtファイルがあることがわかりましたが、出力情報はコンソールに表示されませんでした。したがって、テストは正常に実行されたと結論付けることができますが、何らかの理由で、テストの出力情報はtest_execのコンソールに出力されません。この理由は、TEST_EXECの子プロセスがExecを使用して作成されているため、非常に簡単です。
子プロセスの出力情報を出力する場合は、getInputStreamの出力(子プロセスの出力、親プロセスの入力)を介して子プロセスの出力ストリームを取得し、子の出力ストリームを転送できます。親プロセスのコンソール出力からのプロセス。特定の実装コードは次のとおりです。
// test_exec_out.javaimport java.io。 = new BufferedInputStream(p.getInputStream()); bufferedReader br = new bufferedReader(new inputStreamReader(in)); string s; ;}}
上記のコードからわかるように、test_exec_out.javaでは、子プロセスの出力情報が行ごとに読み取られ、出力は各行でtest_exec_outで実行されます。上記の議論は、子プロセスの出力情報を取得する方法です。次に、出力情報に加えて、入力情報もあります。子プロセスには独自のコンソールがないため、入力情報も親プロセスによって提供される必要があります。プロセスのGetOutputStreamメソッド(つまり、コンソールからの入力情報ではなく、親プロセスから子プロセスへの入力情報)を使用して、子プロセスに入力情報を提供できます。次のコードを見ることができます。
// test2.javaファイルインポートjava.io。*; public class test {public static void main(string [] args){bufferedreader br = new bufferedreader(new inputstreamread er(system.in)); system.out.println( "親プロセスが入力した情報:" + br.readline();}} // test_exec_in.javaimport java.io。 .getRuntime(); Process P = run.exec( "Java test2"); bufferedwriter bw = new bufferedwriter(new outputStreamWriter(p.getOutputStream())); bw.write( "子どものプロセス情報への出力"); bw。 flush(); bw.close();上記のコードから、test1がtest_exec_inによって送信された情報を取得し、出力することがわかります。 bw.flash()とbw.close()を追加しない場合、情報は子プロセスに到達しません。つまり、子プロセスはブロッキング状態になりますが、親プロセスが終了したため、子プロセスも終了します。 。これを証明する場合は、最後にsystem.in.read()を追加してから、タスクマネージャー(Windowsの下)を介してJavaプロセスを表示できます。 .close()、1つのJavaプロセスのみが存在します。削除された場合、2つのJavaプロセスが存在します。これは、情報がtest2に渡された場合、情報を取得した後にtest2が終了するためです。 Execの実行は非同期であり、実行される特定のプログラムがブロックされているため、次のコードの実行を停止しないことを説明することの1つがあります。したがって、test2を実行した後、次のコードを実行できます。
Execメソッドは何度もリロードされています。上記で使用されるのは、単なる過負荷です。また、exec( "java.test2")などのコマンドとパラメーターをexec( "java"、 "test2")として記述できるように分離することもできます。 Execは、指定された環境変数を介して異なる構成でJava仮想マシンを実行することもできます。
RuntimeのExecメソッドを使用して子プロセスを構築することに加えて、ProcessBuilderを介して子プロセスを構築することもできます。 ProcessBuilderの使用は次のとおりです。
// test_exec_out.javaimport java.io。 ;…}}
チャイルドプロセスを確立するには、プロセスビルダーはランタイムに似ています。プロセスを取得した後、彼らの操作はまったく同じです。
Runtimeと同様に、ProcessBuilderは、実行可能ファイルの環境情報、作業ディレクトリなどを設定することもできます。次の例では、ProcessBuilderを使用してこの情報を設定する方法について説明します。
ProcessBuilder PB = new ProcessBuilder( "command"、 "arg2"、 "arg2"、 '' '); //環境変数マップ<文字列> env = pb.environment(); env.put( "key1"、 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::づ 火::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::づ 火::::: ::::::::::::::::::::::::::: "value1"); env.remove( "key2"); env.put( "key2"、env .get( "key1") + "_test"); pb.directory( "../ abcd");
プロセスブロッキングの問題
プロセスで表されるプロセスは、特に標準の入力ストリーム、出力ストリーム、およびプロセスを表すエラー出力を操作する場合、時にはうまくいきます。
上記の例のステートメントが標準出力から情報を再読している場合、エラー出力ストリームから読み取るように変更された場合:
stdout = new BufferedReader(new inputStreamReader(p.getErrorStream()));
その後、プログラムはブロックされ、実行できませんが、そこに掛けます。
プロセスが開始されると、標準の出力ストリームとエラー出力ストリームがオンになって出力を準備し、プロセスが終了すると閉じられます。上記の例では、エラー出力ストリームには出力になるデータがなく、標準出力ストリームにはデータ出力があります。標準出力ストリームのデータは読み取られていないため、プロセスは終了せず、エラー出力ストリームは閉じられません。この問題を解決するために、最初に標準の出力ストリームを読み取り、次に出力の実際の順序に従って間違った出力ストリームを読み取ることができます。
ただし、多くの場合、出力シーケンスは明確にはわかりません。特に標準入力が必要な場合、状況はより複雑になります。この時点で、スレッドを使用して標準出力、エラー出力、標準入力を個別に処理でき、ビジネスロジック関係に応じてストリームまたはデータを読み取ることができます。
標準の出力ストリームと誤った出力ストリームによって引き起こされる問題については、ProcessBuilderのRedirecterrorStream()メソッドを使用して、標準の出力データを読むことができます。
プログラムでProcessのwaitfor()メソッドを使用する場合、特に読み取り前にwaitfor()メソッドを呼び出す場合、閉塞を引き起こす可能性もあります。スレッドメソッドを使用してこの問題を解決するか、データを読んだ後にWATEFOR()メソッドを呼び出して、プログラムが終了するのを待つことができます。
要するに、ここでは、RedirectErrorStreamメソッドを使用して、標準の出力ストリームとError Outputストリームをstart()メソッドで開始した後、標準出力のデータを最初に読み取ります。 、次に、プロセスが終了するのを待つためにWaitfor()メソッドを呼び出します。
のように:
Import Java.io.Io.InputStreamReader; {list <string> list <string>() add( "/c"); ; //標準出力PB.RedirectErrorStream(True)とマージされています(line = stdout.readline()!= null){system.out.println(line)} ret = p.waitfor(); stdou t .close();