Java
 Computer >> コンピューター >  >> プログラミング >> Java

Java 9のProcess APIでプロセスを破棄する方法|ProcessHandleの使い方を解説

Java 9のProcess APIとは

Java 9ではProcess APIが大幅に強化され、OS上で動作するネイティブプロセスに関する詳細な情報を簡単に取得できるようになりました。ProcessHandleインターフェースは、ネイティブプロセスの識別と制御を担い、プロセスの生存状態(liveness)の確認やプロセスの破棄を行うためのメソッドを提供します。また、ProcessHandle.Infoインターフェースを使えば、特定の時点におけるプロセス情報のスナップショットを取得できます。

プロセスを破棄するには、ProcessHandleインターフェースのdestroy()メソッドを呼び出します。このメソッドは対象プロセスに正常な終了を要求するもので、必要に応じてdestroyForcibly()メソッドによる強制終了も選択できます。

ProcessHandleの主なメソッド

  • pid():プロセスID(PID)をlong型で返します。
  • isAlive():プロセスが現在生存しているかどうかを判定します。
  • supportsNormalTermination():そのプロセスが正常な終了処理をサポートしているかどうかを判定します。
  • info():プロセス情報のスナップショットを持つProcessHandle.Infoインスタンスを返します。
  • destroy():プロセスの正常な終了を要求します。
  • destroyForcibly():プロセスを強制的に終了させます。

サンプルコード

以下の例では、ProcessBuilderで子プロセスを起動し、toHandle()メソッドでProcessHandleを取得したうえで、destroy()メソッドを使ってプロセスを終了させています。

import java.io.File;
import java.io.IOException;
import java.util.Objects;

public class DestroyProcessTest {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("---------------------------");
        System.out.println("Destroy Process:");

        final String javaCmd = getJavaCmdFromParent();
        final String classpath = getClassPathFromParent();

        try {
            final Process process = new ProcessBuilder(javaCmd, "-cp", classpath, DestroyProcessTest.class.getName()).start();
            ProcessHandle processHandle = process.toHandle();
            printInfo(processHandle);
            destroyProcess(processHandle);

            Thread.sleep(1000);
            System.out.println("---------------------------");
            System.out.println("After destroying the process:");
            printInfo(processHandle);

        } catch(IOException e) {
            e.printStackTrace();
        }
    }

    private static String getClassPathFromParent() {
        return System.getProperty("java.class.path", "./*");
    }

    private static String getJavaCmdFromParent() {
        return Objects.isNull(System.getProperty("java.home")) ? "java"
                : String.format("%s%sbin%sjava", System.getProperty("java.home"), File.separator, File.separator);
    }

    private static void destroyProcess(ProcessHandle processHandle) throws IllegalStateException {
        System.out.println("Ready to destroy Process with id: " + processHandle.pid());
        processHandle.destroy();
    }

    private static void printInfo(ProcessHandle processHandle) {
        System.out.println("---------");
        System.out.println("Id: " + processHandle.pid());
        System.out.println("isAlive(): " + processHandle.isAlive());
        System.out.println("isSupportsNormalTermination(): " + processHandle.supportsNormalTermination());

        ProcessHandle.Info processInfo = processHandle.info();
        System.out.println("Info: " + processInfo.toString());
        System.out.println("Info arguments().isPresent(): " + processInfo.arguments().isPresent());
        System.out.println("Info command().isPresent(): " + processInfo.command().isPresent());
        System.out.println("Info totalCpuDuration().isPresent(): " + processInfo.totalCpuDuration().isPresent());
        System.out.println("Info user().isPresent(): " + processInfo.user().isPresent());
    }
}

実行結果

---------------------------
Destroy Process:
---------
Id: 4384
isAlive(): true
isSupportsNormalTermination(): false
Info: [user: Optional[Tutorialspoint\User], cmd: C:\Program Files\Java\jdk-9.0.4\bin\java.exe, startTime: Optional[2020-03-06T10:58:53.210Z], totalTime: Optional[PT0.046875S]]
Info arguments().isPresent(): false
Info command().isPresent(): true
Info totalCpuDuration().isPresent(): true
Info user().isPresent(): true
Ready to destroy Process with id: 4384
---------------------------
After destroying the process:
---------
Id: 4384
isAlive(): false
isSupportsNormalTermination(): false
Info: [user: Optional[Tutorialspoint\User], startTime: Optional[2020-03-06T10:58:53.210Z], totalTime: Optional[PT0.109375S]]
Info arguments().isPresent(): false
Info command().isPresent(): false
Info totalCpuDuration().isPresent(): true
Info user().isPresent(): true

実行結果のポイント

出力を見ると、destroy()メソッドを呼び出す前はisAlive()がtrueを返していたのに対し、プロセス破棄後はfalseに変化していることが確認できます。また、破棄後のInfoスナップショットでは、command()など一部の情報が取得できなくなっています。これはプロセスがすでに終了しており、対応する情報が存在しないためです。このようにProcessHandleを活用すれば、プロセスの状態監視から終了処理までを一貫して管理できます。

  1. Java 9のProcess APIでプロセス情報のスナップショットを取得する方法

    Java 9ではProcess APIが大幅に強化され、新しいメソッドが追加されたほか、プロセスとその詳細情報を取得するための新しいインターフェースとしてProcessHandleおよびProcessHandle.Infoが導入されました。 ProcessHandleインターフェースは、ネイティブプロセスを識別し、その制御を可能にします。個々のプロセスに対して、生存状態(liveness)の監視、子プロセスの一覧表示、プロセス情報の取得、さらにはプロセスの破棄(destroy)といった操作を行うことができます。一方、ProcessHandle.Infoインターフェースは、特定の時点におけるプロ

  2. Java 9のProcessBuilderを使ってプロセスを作成・管理する方法

    Java 9では、Process APIが強化され、新たにProcessHandleインターフェースが追加されました。ProcessHandleのインスタンスはローカルプロセスを識別し、プロセスの状態(ステータス)の照会やプロセス管理を可能にします。従来はローカルプロセスのPIDを取得するためにネイティブコードが必要でしたが、ProcessHandle.Infoを使えば、その必要なくPIDやその他のプロセス情報を簡単に取得できるようになりました。 ProcessBuilderクラスは、オペレーティングシステム上で独立したプロセスを作成するために使用されるクラスです。以下の例では、Process