広告

Java : ProcessHandle (外部プロセス) - API使用例

ProcessHandle (Java SE 19 & JDK 19) の使用例まとめです。
だいたいのメソッドを網羅済みです。
API仕様のおともにどうぞ。


概要

ProcessHandleは、ネイティブ・プロセスを識別して制御します。 それぞれのプロセスは、活力を監視し、子を列挙したり、プロセスに関する情報を入手したり、破壊することができます。

クラス構成

ProcessHandle インタフェースは、外部プロセスの制御に使います。
プロセスの情報を取得したり、プロセスを強制終了させたりすることができます。

似たクラスに Process クラスがあります。

Process クラスは、ProcessBuilder で起動したプロセスです。
自分で起動したプロセスのため、標準出力や標準入力の制御もできます。

ProcessHandle は ProcessBuilder で起動していないプロセスの制御もできます。
代わりに、標準出力や標準入力の制御はできません。

public class Main {
    public static void main(String[] args) {
        final var handle = ProcessHandle.current();
        final var pid = handle.pid();
        System.out.println("pid = " + pid);

        final var info = handle.info();
        System.out.println("user = " + info.user());
        System.out.println("total cpu time = " + info.totalCpuDuration());
    }
}

// 結果
// ↓
//> java Main
//pid = 11908
//user = Optional[MY-PC\xxxx]
//total cpu time = Optional[PT0.125S]

メソッド

static Stream<ProcessHandle> allProcesses ()

現在のプロセスから見えるすべてのプロセスのスナップショットを返します。

final var stream = ProcessHandle.allProcesses();
stream.forEach(handle -> {
    handle.info().command().ifPresent(command -> {
        System.out.println("command : " + command);
    });
});

// 結果
// ↓
//command : C:\Windows\System32\sihost.exe
//command : C:\Windows\System32\svchost.exe
//command : C:\Windows\System32\taskhostw.exe
//...
//command : C:\Windows\System32\notepad.exe
//command : C:\Windows\System32\mspaint.exe
//...

Stream<ProcessHandle> children ()

プロセスの現在の直接子のスナップショットを返します。

public class ChildA {
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
    }
}
public class ChildB {
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println("main : start");

        final var processA = new ProcessBuilder("java", "ChildA").inheritIO().start();
        System.out.println("  child A pid = " + processA.pid());

        final var processB = new ProcessBuilder("java", "ChildB").inheritIO().start();
        System.out.println("  child B pid = " + processB.pid());

        TimeUnit.SECONDS.sleep(1);

        System.out.println("-- children --");
        final var stream = ProcessHandle.current().children();
        stream.forEach(handle -> System.out.println("pid : " + handle.pid()));
        System.out.println("--------------");

        processA.waitFor();
        processB.waitFor();

        System.out.println("main : end");
    }
}

// 結果
// ↓
//> java Main
//main : start
//  child A pid = 4784
//  child B pid = 10488
//-- children --
//pid : 4784
//pid : 10488
//--------------
//main : end

int compareTo (ProcessHandle other)

このProcessHandleと指定したオーダーのProcessHandleを比較します。

public class Child {
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        final var process = new ProcessBuilder("java", "Child").start();

        final var current = ProcessHandle.current();
        System.out.println("current : pid = " + current.pid());

        final var child = process.toHandle();
        System.out.println("child : pid = " + child.pid());

        System.out.println("compare to 1 : " + current.compareTo(child));
        System.out.println("compare to 2 : " + child.compareTo(current));
        System.out.println("compare to 3 : " + current.compareTo(current));

        process.waitFor();
    }
}

// 結果
// ↓
//> java Main
//current : pid = 14972
//child : pid = 7272
//compare to 1 : 1
//compare to 2 : -1
//compare to 3 : 0

static ProcessHandle current ()

現在のプロセスのProcessHandleを返します。

public class Child {
    public static void main(String[] args) {
        System.out.println("child : start");

        final var current = ProcessHandle.current();
        System.out.println("  child current pid = " + current.pid());

        current.parent().ifPresent(parent -> {
            System.out.println("  child parent pid = " + parent.pid());
        });

        System.out.println("child : end");
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println("main : start");

        final var process = new ProcessBuilder("java", "Child").inheritIO().start();
        System.out.println("main : child pid = " + process.pid());

        final var current = ProcessHandle.current();
        System.out.println("main : current pid = " + current.pid());

        process.waitFor();

        System.out.println("main : end");
    }
}

// 結果
// ↓
//> java Main
//main : start
//main : child pid = 16612
//main : current pid = 3476
//child : start
//  child current pid = 16612
//  child parent pid = 3476
//child : end
//main : end

Stream<ProcessHandle> descendants ()

プロセスの子孫のスナップショットを返します。

public class DescendantA {
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
    }
}
public class DescendantB {
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
    }
}
public class Child {
    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println("child : start");

        final var processA = new ProcessBuilder("java", "DescendantA").inheritIO().start();
        System.out.println("  descendant A pid = " + processA.pid());

        final var processB = new ProcessBuilder("java", "DescendantB").inheritIO().start();
        System.out.println("  descendant B pid = " + processB.pid());

        processA.waitFor();
        processB.waitFor();

        System.out.println("child : end");
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println("main : start");

        final var process = new ProcessBuilder("java", "Child").inheritIO().start();
        System.out.println("  child pid = " + process.pid());

        TimeUnit.SECONDS.sleep(1);

        System.out.println("-- descendants --");
        final var stream = ProcessHandle.current().descendants();
        stream.forEach(handle -> {
            System.out.println("pid : " + handle.pid());
        });
        System.out.println("--------------");

        process.waitFor();

        System.out.println("main : end");
    }
}

// 結果
// ↓
//> java Main
//main : start
//  child pid = 21016
//child : start
//  descendant A pid = 15960
//  descendant B pid = 17192
//-- descendants --
//pid : 21016
//pid : 15960
//pid : 17192
//--------------
//child : end
//main : end

boolean destroy ()

プロセスを強制終了するようにリクエストします。

public class Child {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("child : start");

        TimeUnit.SECONDS.sleep(5);

        System.out.println("child : end");
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println("main : start");

        final var process = new ProcessBuilder("java", "Child").inheritIO().start();
        TimeUnit.SECONDS.sleep(1);

        if (args.length == 1 && "destroy".equals(args[0])) {
            final var handle = process.toHandle();
            System.out.println("destroy : " + handle.destroy());
        }
        System.out.println("waitFor : " + process.waitFor());

        System.out.println("main : end");
    }
}

// 結果
// ↓
//> java Main
//main : start
//child : start
//child : end
//waitFor : 0
//main : end
//
//> java Main destroy
//main : start
//child : start
//destroy : true
//waitFor : 1
//main : end

boolean destroyForcibly ()

プロセスを強制的に強制終了するようにリクエストします。

public class Child {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("child : start");

        TimeUnit.SECONDS.sleep(5);

        System.out.println("child : end");
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println("main : start");

        final var process = new ProcessBuilder("java", "Child").inheritIO().start();
        TimeUnit.SECONDS.sleep(1);

        if (args.length == 1 && "destroy".equals(args[0])) {
            final var handle = process.toHandle();
            System.out.println("destroy : " + handle.destroyForcibly());
        }
        System.out.println("waitFor : " + process.waitFor());

        System.out.println("main : end");
    }
}

// 結果
// ↓
//> java Main
//main : start
//child : start
//child : end
//waitFor : 0
//main : end
//
//> java Main destroy
//main : start
//child : start
//destroy : true
//waitFor : 1
//main : end

boolean equals (Object other)

otherオブジェクトが非nullで、同じ実装であり、同じシステム・プロセスを表す場合は、trueを返します; それ以外の場合は、falseを返します。

public class Child {
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        final var process = new ProcessBuilder("java", "Child").start();

        final var current = ProcessHandle.current();
        System.out.println("current : pid = " + current.pid());

        final var child = process.toHandle();
        System.out.println("child : pid = " + child.pid());

        System.out.println("equals 1 : " + current.equals(child));
        System.out.println("equals 2 : " + child.equals(current));
        System.out.println("equals 3 : " + current.equals(current));

        process.waitFor();
    }
}

// 結果
// ↓
//> java Main
//current : pid = 19488
//child : pid = 5440
//equals 1 : false
//equals 2 : false
//equals 3 : true

int hashCode ()

このProcessHandleのハッシュ・コード値を返します。

public class Child {
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        final var process = new ProcessBuilder("java", "Child").start();

        final var current = ProcessHandle.current();
        System.out.println("current : pid = " + current.pid());
        System.out.println("current : hashCode = " + current.hashCode());

        final var child = process.toHandle();
        System.out.println("child : pid = " + child.pid());
        System.out.println("child : hashCode = " + child.hashCode());

        process.waitFor();
    }
}

// 結果
// ↓
//> java Main
//current : pid = 7260
//current : hashCode = 7260
//child : pid = 16924
//child : hashCode = 16924

ProcessHandle.Info info ()

プロセスに関する情報のスナップショットを返します。

public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        final var current = ProcessHandle.current();
        System.out.println("pid : " + current.pid());

        final var info = current.info();
        System.out.println("user : " + info.user());
        System.out.println("total cpu time : " + info.totalCpuDuration());
    }
}

// 結果
// ↓
//> java Main
//pid : 12276
//user : Optional[MY-PC\xxxx]
//total cpu time : Optional[PT0.125S]

boolean isAlive ()

このProcessHandleが表すプロセスが生存しているかどうかをテストします。

public class Child {
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(5);
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
        System.out.println("main : start");

        final var process = new ProcessBuilder("java", "Child").start();
        TimeUnit.SECONDS.sleep(1);

        final var child = process.toHandle();
        System.out.println("child : pid = " + child.pid());
        System.out.println("child : isAlive = " + child.isAlive());

        final var ret = child.onExit().thenApply(handle -> {
            System.out.println("apply : pid = " + handle.pid());
            System.out.println("apply : isAlive = " + handle.isAlive());
            return handle;
        }).get();
        System.out.println("ret = " + ret.pid());

        System.out.println("main : end");
    }
}

// 結果
// ↓
//> java Main
//main : start
//child : pid = 1572
//child : isAlive = true
//apply : pid = 1572
//apply : isAlive = false
//ret = 1572
//main : end

static Optional<ProcessHandle> of (long pid)

既存のネイティブ・プロセスのOptional<ProcessHandle>を返します。

public class Child {
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        final var process = new ProcessBuilder("java", "Child").start();
        final var pid = process.pid();
        System.out.println("pid = " + pid);

        ProcessHandle.of(pid).ifPresent(handle -> {
            System.out.println("handle : pid = " + handle.pid());
        });

        process.waitFor();
    }
}

// 結果
// ↓
//> java Main
//pid = 22196
//handle : pid = 22196

CompletableFuture<ProcessHandle> onExit ()

プロセスの終了のためのCompletableFuture<ProcessHandle>を返します。

このメソッドの使用例は、isAlive() にまとめて記載しました。
そちらのAPI使用例をご参照ください。

Optional<ProcessHandle> parent ()

親プロセス用のOptional<ProcessHandle>を返します。

このメソッドの使用例は、current() にまとめて記載しました。
そちらのAPI使用例をご参照ください。

long pid ()

プロセスのネイティブ・プロセスIDを返します。

このメソッドの使用例は、current() にまとめて記載しました。
そちらのAPI使用例をご参照ください。

boolean supportsNormalTermination ()

destroy()の実装が正常にプロセスを終了する場合は、trueを返します。

final var current = ProcessHandle.current();
System.out.println(current.supportsNormalTermination()); // false

関連記事

ページの先頭へ