java.lang.Process APIガイド

java.lang.Process APIのガイド

1. 前書き

このチュートリアルでは、an in-depth look at the Process APIを使用します。

Processを使用してシェルコマンドを実行する方法の詳細については、前のチュートリアルhereを参照してください。

参照するプロセスは、実行中のアプリケーションです。 Processクラスは、出力の抽出、入力の実行、ライフサイクルの監視、終了ステータスの確認、破棄(強制終了)など、これらのプロセスと対話するためのメソッドを提供します。

2. Javaプログラムのコンパイルと実行にProcessクラスを使用する

ProcessAPIを使用して別のJavaプログラムをコンパイルして実行する例を見てみましょう。

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

したがって、既存のJavaコード内でJavaコードを実行するアプリケーションは、事実上無限です。

3. プロセスの作成

Javaアプリケーションは、オペレーティングシステムの制限の対象となるコンピューターシステム内で実行されているアプリケーションを呼び出すことができます。

したがって、アプリケーションを実行できます。 ProcessAPIを利用して実行できるさまざまなユースケースを見てみましょう。

ProcessBuilderクラスを使用すると、アプリケーション内にサブプロセスを作成できます。

Windowsベースのメモ帳アプリケーションを開くデモを見てみましょう。

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

4. 破壊プロセス

Processは、サブプロセスまたはプロセスを破棄するメソッドも提供します。 Although, how the application is killed is platform-dependent

可能なさまざまなユースケースを見てみましょう。

4.1. 参照によるプロセスの破棄

Windows OSを使用していて、メモ帳アプリケーションを生成して破棄したいとします。

以前と同様に、ProcessBuilderクラスとstart()メソッドを使用して、メモ帳アプリケーションのインスタンスを作成できます。

次に、Processオブジェクトでdestroy()メソッドを呼び出すことができます。

4.2. IDによるプロセスの破棄

また、アプリケーションによって作成されていない可能性のあるオペレーティングシステム内で実行されているプロセスを強制終了することもできます。

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

まず、タスクマネージャーをチェックして現在実行中のプロセスのプロセスIDを見つけ、pidを見つけます。

例を見てみましょう:

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

4.3. プロセスを強制的に破壊する

destroy()メソッドを実行すると、記事の前半で見たように、サブプロセスが強制終了されます。

destroy()が機能しない場合は、destroyForcibly()のオプションがあります。

常に最初にdestroy()メソッドから始める必要があります。 その後、isAlive()を実行するかどうか、サブプロセスのクイックチェックを実行できます。

trueが返された場合は、destroyForcibly()を実行します。

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

5. プロセスが完了するのを待っています

また、2つのオーバーロードされたメソッドがあります。これらのメソッドを使用して、プロセスの完了を待つことができます。

5.1. waitfor()

このメソッドが実行されると、the current execution process thread in a blocking-wait state unless the sub-process gets terminatedが配置されます。

例を見てみましょう:

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

現在のスレッドの実行を継続するための上記の例から、サブプロセスのスレッドが終了するまで待機し続けることがわかります。 サブプロセスが終了すると、現在のスレッドは実行を継続します。

5.2. waitfor(long timeOut, TimeUnit time)

このメソッドが実行されると、the current execution process thread in the blocking-wait state unless the sub-process gets terminated or runs out of timeが配置されます。

例を見てみましょう:

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

実行を継続する現在のスレッドの上記の例から、サブプロセススレッドが終了するのを待機し続けるか、指定された時間間隔が経過したかどうかを確認できます。

このメソッドが実行されると、サブプロセスが終了した場合はブール値trueが返され、サブプロセスが終了する前に待機時間が経過した場合はブール値falseが返されます。

6. exitValue()

このメソッドが実行されると、現在のスレッドはサブプロセスが終了または破棄されるのを待ちませんが、サブプロセスが終了しない場合はIllegalThreadStateExceptionをスローします。

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

任意の正の整数を指定できます。

サブプロセスが正常に終了したときにexitValue()メソッドが正の整数を返す例を見てみましょう。

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

7. isAlive()

プロセスが生きているかどうかにかかわらず主観的なビジネス処理を実行したい場合。

ブール値を返すプロセスが動作しているかどうかを調べるために、簡単なチェックを実行できます。

その簡単な例を見てみましょう。

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

8. プロセスストリームの処理

デフォルトでは、作成されたサブプロセスには端末またはコンソールがありません。 すべての標準I / O(つまり、stdin、stdout、stderr)操作は、親プロセスに送信されます。 これにより、親プロセスはこれらのストリームを使用して、サブプロセスに入力を供給し、サブプロセスから出力を取得できます。

その結果、サブプロセスの入力/出力を制御できるため、柔軟性が大幅に向上します。

8.1. getErrorStream()

興味深いことに、サブプロセスから生成されたエラーを取得して、ビジネスプロセスを実行できます。

その後、要件に基づいて特定のビジネス処理チェックを実行できます。

例を見てみましょう:

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

また、サブプロセスによって生成された出力をフェッチし、親プロセス内で消費することで、プロセス間で情報を共有できます。

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

親プロセスからサブプロセスに入力を送信できます。

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

8.4. プロセスストリームのフィルタリング

これは、選択的に実行されているプロセスと対話するための完全に有効なユースケースです。

Processは、特定の述語に基づいて実行中のプロセスを選択的にフィルタリングする機能を提供します。

その後、この選択プロセスセットでビジネスオペレーションを実行できます。

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

9. 結論

Processは、オペレーティングシステムレベルの対話のための強力なクラスです。 端末コマンドのトリガー、およびアプリケーションの起動、監視、強制終了。

Java 9 Process APIの詳細については、記事hereを参照してください。

いつものように、ソースover on Githubが見つかります。