Как программа Java может получить свой собственный идентификатор процесса?

Как получить идентификатор моего Java-процесса?

Я знаю, что есть несколько зависящих от платформы хаков, но я бы предпочел более общее решение.

Ответ 1

Существует не зависящий от платформы способ, который может быть гарантирован для работы во всех реализациях jvm. ManagementFactory.getRuntimeMXBean().getName() выглядит как лучшее (самое близкое) решение. Он короткий и, вероятно, работает в каждой реализации в широком использовании.

В linux + windows возвращается значение типа [email protected] (12345, являющееся идентификатором процесса). Остерегайтесь, что в соответствии с документами, никаких гарантий относительно этого значения нет:

Возвращает имя, представляющее запущенную виртуальную машину Java. Возвращаемая строка имени может быть любой произвольной строкой и виртуальной виртуальной машиной Java машинная реализация может выбрать встроенную платформу информацию в возвращаемой строке имени. Каждая работающая виртуальная машина может иметь другое имя.

В Java 9 можно использовать новый процесс API:

long pid = ProcessHandle.current().pid();

Ответ 2

Вы могли бы использовать JNA. К сожалению, пока нет общего JNA API для получения текущего идентификатора процесса, но каждая платформа довольно проста:

Windows

Убедитесь, что у вас есть jna-platform.jar:

int pid = Kernel32.INSTANCE.GetCurrentProcessId();

Юникс

Объявляет:

private interface CLibrary extends Library {
    CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);   
    int getpid ();
}

Затем:

int pid = CLibrary.INSTANCE.getpid();

Java 9

В Java 9 новый API процесса может использоваться для получения текущего идентификатора процесса. Сначала вы берете дескриптор текущего процесса, а затем запрашиваете PID:

long pid = ProcessHandle.current().pid();

Ответ 3

Вот бэкдор-метод, который может не работать со всеми виртуальными машинами, но должен работать как с linux, так и с окнами (оригинальный пример здесь):

java.lang.management.RuntimeMXBean runtime = 
    java.lang.management.ManagementFactory.getRuntimeMXBean();
java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm");
jvm.setAccessible(true);
sun.management.VMManagement mgmt =  
    (sun.management.VMManagement) jvm.get(runtime);
java.lang.reflect.Method pid_method =  
    mgmt.getClass().getDeclaredMethod("getProcessId");
pid_method.setAccessible(true);

int pid = (Integer) pid_method.invoke(mgmt);

Ответ 4

Попробуйте Sigar. очень обширные API. Лицензия Apache 2.

    private Sigar sigar;

    public synchronized Sigar getSigar() {
        if (sigar == null) {
            sigar = new Sigar();
        }
        return sigar;
    }

    public synchronized void forceRelease() {
        if (sigar != null) {
            sigar.close();
            sigar = null;
        }
    }

    public long getPid() {
        return getSigar().getPid();
    }

Ответ 5

Следующий метод пытается извлечь PID из java.lang.management.ManagementFactory:

private static String getProcessId(final String fallback) {
    // Note: may fail in some JVM implementations
    // therefore fallback has to be provided

    // something like '<pid>@<hostname>', at least in SUN / Oracle JVMs
    final String jvmName = ManagementFactory.getRuntimeMXBean().getName();
    final int index = jvmName.indexOf('@');

    if (index < 1) {
        // part before '@' empty (index = 0) / '@' not found (index = -1)
        return fallback;
    }

    try {
        return Long.toString(Long.parseLong(jvmName.substring(0, index)));
    } catch (NumberFormatException e) {
        // ignore
    }
    return fallback;
}

Просто вызовите getProcessId("<PID>"), например.

Ответ 6

Вы можете проверить мой проект: JavaSysMon на GitHub. Он предоставляет идентификатор процесса и кучу других вещей (использование процессора, использование памяти) кросс-платформенную (в настоящее время Windows, Mac OSX, Linux и Solaris)

Ответ 7

Для более старых JVM, в linux...

private static String getPid() throws IOException {
    byte[] bo = new byte[256];
    InputStream is = new FileInputStream("/proc/self/stat");
    is.read(bo);
    for (int i = 0; i < bo.length; i++) {
        if ((bo[i] < '0') || (bo[i] > '9')) {
            return new String(bo, 0, i);
        }
    }
    return "-1";
}

Ответ 8

Так как Java 9 существует метод Process.getPid(), который возвращает собственный идентификатор процесса:

public abstract class Process {

    ...

    public long getPid();
}

Чтобы получить идентификатор процесса текущего процесса Java, можно использовать интерфейс ProcessHandle:

System.out.println(ProcessHandle.current().pid());

Ответ 9

Для полноты есть оболочка Spring Boot для

String jvmName = ManagementFactory.getRuntimeMXBean().getName();
return jvmName.split("@")[0];

решение. Если требуется целое число, то это можно суммировать с одним слоем:

int pid = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);

Если кто-то использует Spring boot уже, он/он может использовать org.springframework.boot.ApplicationPid

ApplicationPid pid = new ApplicationPid();
pid.toString();

Метод toString() печатает pid или '???'.

Предостережения с использованием ManagementFactory уже обсуждаются в других ответах.

Ответ 10

public static long getPID() {
    String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
    if (processName != null && processName.length() > 0) {
        try {
            return Long.parseLong(processName.split("@")[0]);
        }
        catch (Exception e) {
            return 0;
        }
    }

    return 0;
}

Ответ 11

Последнее, что я обнаружил, это системное свойство sun.java.launcher.pid, доступное по крайней мере на linux. Мой план состоит в том, чтобы использовать это, и если он не найден, используйте JMX bean.

Ответ 12

В Scala:

import sys.process._
val pid: Long = Seq("sh", "-c", "echo $PPID").!!.trim.toLong

Это должно дать вам обходное решение для Unix-систем, пока не будет выпущена Java 9. (Я знаю, вопрос был о Java, но поскольку нет эквивалентного вопроса для Scala, я хотел оставить это для Scala пользователей, которые могли бы споткнуться в один и тот же вопрос.)

Ответ 13

Это зависит от того, откуда вы ищете информацию.

Если вы ищете информацию с консоли, вы можете использовать команду jps. Команда дает результат, подобный команде Unix ps, и поставляется с JDK, так как я полагаю, что 1.5

Если вы смотрите на процесс, RuntimeMXBean (как сказал Wouter Coekaerts), вероятно, ваш лучший выбор. Результат getName() для Windows с использованием Sun JDK 1.6 u7 находится в форме [PROCESS_ID] @[MACHINE_NAME]. Однако вы можете попытаться выполнить jps и проанализировать результат:

String jps = [JDK HOME] + "\\bin\\jps.exe";
Process p = Runtime.getRuntime().exec(jps);

Если запустить без параметров, то результатом должен быть идентификатор процесса, за которым следует имя.

Ответ 14

java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]

Ответ 15

Это код JConsole, и, возможно, использует jps и VisualVM. В нем используются классы из sun.jvmstat.monitor.*, от tool.jar.

package my.code.a003.process;

import sun.jvmstat.monitor.HostIdentifier;
import sun.jvmstat.monitor.MonitorException;
import sun.jvmstat.monitor.MonitoredHost;
import sun.jvmstat.monitor.MonitoredVm;
import sun.jvmstat.monitor.MonitoredVmUtil;
import sun.jvmstat.monitor.VmIdentifier;


public class GetOwnPid {

    public static void main(String[] args) {
        new GetOwnPid().run();
    }

    public void run() {
        System.out.println(getPid(this.getClass()));
    }

    public Integer getPid(Class<?> mainClass) {
        MonitoredHost monitoredHost;
        Set<Integer> activeVmPids;
        try {
            monitoredHost = MonitoredHost.getMonitoredHost(new HostIdentifier((String) null));
            activeVmPids = monitoredHost.activeVms();
            MonitoredVm mvm = null;
            for (Integer vmPid : activeVmPids) {
                try {
                    mvm = monitoredHost.getMonitoredVm(new VmIdentifier(vmPid.toString()));
                    String mvmMainClass = MonitoredVmUtil.mainClass(mvm, true);
                    if (mainClass.getName().equals(mvmMainClass)) {
                        return vmPid;
                    }
                } finally {
                    if (mvm != null) {
                        mvm.detach();
                    }
                }
            }
        } catch (java.net.URISyntaxException e) {
            throw new InternalError(e.getMessage());
        } catch (MonitorException e) {
            throw new InternalError(e.getMessage());
        }
        return null;
    }
}

Есть несколько уловов:

  • tool.jar - это библиотека, распространяемая с Oracle JDK, но не JRE!
  • Вы не можете получить tool.jar из Maven repo; настроить его с помощью Maven немного сложно
  • tool.jar, вероятно, содержит зависимый от платформы (native?) код, так что это нелегко  распространяемый
  • Он работает в предположении, что все (локальные) запущенные JVM-приложения "контролируются". Это выглядит как  что из Java 6 все приложения обычно (если вы не настроите их на противоположную)
  • Возможно, он работает только для Java 6 +
  • Eclipse не публикует основной класс, поэтому вы не сможете легко получить Eclipse PID Ошибка в MonitoredVmUtil?

UPDATE: я просто дважды проверил, что JPS использует этот путь, то есть библиотеку Jvmstat (часть tool.jar). Поэтому нет необходимости вызывать JPS в качестве внешнего процесса, вызывать библиотеку Jvmstat непосредственно, как показывает мой пример. Вы также можете получить список всех JVM runnin на localhost таким образом. См. JPS исходный код:

Ответ 16

На основе Ashwin Jayaprakash answer (+1) об лицензированном Apache 2.0 SIGAR, вот как я использую его для получения только PID текущего процесса:

import org.hyperic.sigar.Sigar;

Sigar sigar = new Sigar();
long pid = sigar.getPid();
sigar.close();

Несмотря на то, что он не работает на всех платформах, он работает на Linux, Windows, OS X и различных платформах Unix, перечисленных здесь.

Ответ 17

Вы можете попробовать getpid() в JNR-Posix.

У этого есть оболочка Windows POSIX, которая вызывает getpid() от libc.

Ответ 18

Я знаю, что это старый поток, но я хотел назвать, что API для получения PID (а также других манипуляций с процессом Java во время выполнения) добавляется в класс Process в JDK 9: http://openjdk.java.net/jeps/102

Ответ 19

Добавление к другим решениям.

с Java 10, чтобы получить process id

final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
final long pid = runtime.getPid();
out.println("Process ID is '" + pid);

Ответ 20

Я нашел решение, которое может показаться немного странным, и я не пробовал его на других ОС, кроме Windows 10, но думаю, что стоит обратить на это внимание.

Если вы работаете с J2V8 и nodejs, вы можете запустить простую функцию javascript, возвращающую вам pid процесса java.

Вот пример:

public static void main(String[] args) {
    NodeJS nodeJS = NodeJS.createNodeJS();
    int pid = nodeJS.getRuntime().executeIntegerScript("process.pid;\n");
    System.out.println(pid);
    nodeJS.release();
}

Ответ 21

Вот мое решение:

public static boolean isPIDInUse(int pid) {

        try {

            String s = null;
            int java_pid;

            RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
            java_pid = Integer.parseInt(rt.getName().substring(0, rt.getName().indexOf("@")));

            if (java_pid == pid) {
                System.out.println("In Use\n");
                return true;
            }
        } catch (Exception e) {
            System.out.println("Exception:  " + e.getMessage());
        }
        return false;
    }

Ответ 22

Это то, что я использовал, когда у меня было подобное требование. Это правильно определяет PID процесса Java. Пусть ваш Java-код порождает сервер по предварительно определенному номеру порта, а затем выполняет команды ОС, чтобы узнать, что PID прослушивает порт. Для Linux

netstat -tupln | grep portNumber