Как получить PID процесса, который я только что начал в Java-программе? - PullRequest
66 голосов
/ 20 января 2011

Я запустил процесс со следующим кодом

 ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "path");
 try {
     Process p = pb.start();       
 } 
 catch (IOException ex) {}

Теперь мне нужно знать pid процесса, который я только что начал.

Ответы [ 16 ]

0 голосов
/ 12 декабря 2017

Одним из решений является использование уникальных инструментов, предлагаемых платформой:

private static String invokeLinuxPsProcess(String filterByCommand) {
    List<String> args = Arrays.asList("ps -e -o stat,pid,unit,args=".split(" +"));
    // Example output:
    // Sl   22245 bpds-api.service                /opt/libreoffice5.4/program/soffice.bin --headless
    // Z    22250 -                               [soffice.bin] <defunct>

    try {
        Process psAux = new ProcessBuilder(args).redirectErrorStream(true).start();
        try {
            Thread.sleep(100); // TODO: Find some passive way.
        } catch (InterruptedException e) { }

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(psAux.getInputStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (!line.contains(filterByCommand))
                    continue;
                String[] parts = line.split("\\w+");
                if (parts.length < 4)
                    throw new RuntimeException("Unexpected format of the `ps` line, expected at least 4 columns:\n\t" + line);
                String pid = parts[1];
                return pid;
            }
        }
    }
    catch (IOException ex) {
        log.warn(String.format("Failed executing %s: %s", args, ex.getMessage()), ex);
    }
    return null;
}

Отказ от ответственности: не проверено, но вы получаете идею:

  • Позвоните ps, чтобы получить списокпроцессы,
  • Найдите свой, потому что вы знаете команду, с которой вы его запустили.
  • Если существует несколько процессов с одной и той же командой, вы можете:
    • Добавить еще одну пустышкуаргумент для их дифференциации
    • полагаться на увеличение PID (не совсем безопасно, не одновременно)
    • проверить время создания процесса (может быть слишком грубым, чтобы действительно дифференцировать, а также не одновременно)
    • Добавьте определенную переменную среды и перечислите ее с помощью ps.
0 голосов
/ 02 ноября 2017

Существует библиотека с открытым исходным кодом, которая имеет такую ​​функцию, и имеет кросс-платформенную реализацию: https://github.com/OpenHFT/Java-Thread-Affinity

Возможно, будет слишком сложно просто получить PID, но если вам нужны другие вещи, такие какИдентификатор ЦП и потока и, в частности, сходство потоков, может быть достаточно для вас.

Чтобы получить PID текущего потока, просто наберите Affinity.getAffinityImpl().getProcessId().

Это реализовано с использованием JNA (см. Arcsin'sответить).

0 голосов
/ 07 сентября 2017

Если переносимость не является проблемой, и вы просто хотите получить pid в Windows без особых хлопот при использовании кода, который протестирован и работает на всех современных версиях Windows, вы можете использовать winp от kohsuke библиотека.Это также доступно на Центральном Maven для легкого потребления.

Process process = //...;
WinProcess wp = new WinProcess(process);
int pid = wp.getPid();
0 голосов
/ 08 августа 2017

Я считаю, что единственный переносимый способ сделать это - запустить (дочерний) процесс через другой (родительский) процесс Java, который сообщит мне фактический PID родительского процесса.Дочерний процесс может быть любым.

Код этой оболочки:

package com.panayotis.wrapper;

import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;

public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
        ProcessBuilder pb = new ProcessBuilder(args);
        pb.directory(new File(System.getProperty("user.dir")));
        pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectError(ProcessBuilder.Redirect.INHERIT);
        pb.start().waitFor();
    }
}

Чтобы использовать его, создайте файл jar только с этим и вызовите его с аргументами команды:1006 *

String java = System.getProperty("java.home") + separator + "bin" + separator + "java.exe";
String jar_wrapper = "path\\of\\wrapper.jar";

String[] args = new String[]{java, "-cp", jar_wrapper, "com.panayotis.wrapper.Main", actual_exec_args...);
0 голосов
/ 19 августа 2015

проект jnr-process предоставляет такую ​​возможность.

Он является частью нативной среды выполнения java, используемой jruby, и может рассматриваться как прототип для будущего java-FFI

0 голосов
/ 20 января 2011

Простого решения не существует.То, как я делал это в прошлом, - это запустить другой процесс для запуска команды ps в Unix-подобных системах или команды tasklist в Windows, а затем проанализировать выходные данные этой команды для PID Iхочу.В действительности я закончил тем, что поместил этот код в отдельный сценарий оболочки для каждой платформы, которая просто возвращала PID, чтобы я мог сохранить часть Java как независимую от платформы.Это не очень хорошо для краткосрочных задач, но это не проблема для меня.

...