English 中文(简体)
Java程序如何获得自己的进程ID?
原标题:
  • 时间:2008-08-30 09:53:25
  •  标签:

如何获取Java进程的id?

我知道有几个依赖于平台的技巧,但我更喜欢一个更通用的解决方案。

最佳回答

There exists no platform-independent way that can be guaranteed to work in all jvm implementations. ManagementFactory.getRuntimeMXBean().getName() looks like the best (closest) solution, and typically includes the PID. It s short, and probably works in every implementation in wide use.

在linux+windows上,它返回一个值,如<code>“12345@hostname“(1234是进程id)。不过要小心根据文档,无法保证此值:

Returns the name representing the running Java virtual machine. The returned name string can be any arbitrary string and a Java virtual machine implementation can choose to embed platform-specific useful information in the returned name string. Each running virtual machine could have a different name.

在Java 9中新的可以使用过程API

long pid = ProcessHandle.current().pid();
问题回答

您可以使用JNA。不幸的是,目前还没有通用的JNA API来获取当前进程ID,但每个平台都很简单:

Windows

确保您有jna平台.jar,然后:

int pid = Kernel32.INSTANCE.GetCurrentProcessId();

Unix

声明:

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可用于获取当前进程ID。首先获取当前进程的句柄,然后查询PID:

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

这里有一个后门方法,可能不适用于所有虚拟机,但应该同时适用于linux和windows(此处的原始示例):

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

尝试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();
}

以下方法尝试从<code>java.lang.management.ManagementFactory</code>中提取PID:

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>;”)

对于较旧的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";
}

自从Java 9以来,有一个方法Process.getPid(),它返回进程的本地ID:

public abstract class Process {

    ...

    public long getPid();
}

要获取当前Java进程的进程ID,可以使用ProcessHandle接口:

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

您可以查看我的项目:JavaSysMon在GitHub上。它提供跨平台(目前是Windows、Mac OSX、Linux和Solaris)的进程id和一系列其他内容(CPU使用情况、内存使用情况)

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

在Scala中:

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

This should give you a workaround on Unix systems until Java 9 will be released. (I know, the question was about Java, but since there is no equivalent question for Scala, I wanted to leave this for Scala users who might stumble into the same question.)

为了完整起见,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的注意事项。

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

除了其他解决方案之外,我还添加了这个。

with Java 10, to get process id

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

我发现的最新情况是,有一个系统属性,名为sun.java。launcher.pid,至少在linux上可用。我的计划是使用它,如果找不到它,就使用JMXbean

这取决于你从哪里寻找信息。

如果您正在从控制台中查找信息,则可以使用jps命令。该命令提供类似于Unix ps命令的输出,并且随JDK一起提供,因为我相信1.5

如果你从流程来看,RuntimeMXBean(正如Wouter Coekaerts所说)可能是你的最佳选择。在使用Sun JDK 1.6 u7的Windows上,getName()的输出形式为[PROCESS_ID]@[MACHINE_NAME]。然而,您可以尝试执行jps并解析其结果:

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

如果在没有选项的情况下运行,则输出应该是进程id后面跟着名称。

This is the code JConsole, and potentially jps and VisualVM uses. It utilizes classes from sun.jvmstat.monitor.* package, from 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;
    }
}

有几个陷阱:

  • The tool.jar is a library distributed with Oracle JDK but not JRE!
  • You cannot get tool.jar from Maven repo; configure it with Maven is a bit tricky
  • The tool.jar probably contains platform dependent (native?) code so it is not easily distributable
  • It runs under assumption that all (local) running JVM apps are "monitorable". It looks like that from Java 6 all apps generally are (unless you actively configure opposite)
  • It probably works only for Java 6+
  • Eclipse does not publish main class, so you will not get Eclipse PID easily Bug in MonitoredVmUtil?

UPDATE: I have just double checked that JPS uses this way, that is Jvmstat library (part of tool.jar). So there is no need to call JPS as external process, call Jvmstat library directly as my example shows. You can aslo get list of all JVMs runnin on localhost this way. See JPS source code:

我知道这是一个旧线程,但我想调用用于获取PID的API(以及在运行时对Java进程的其他操作),该API正在被添加到JDK 9中的process类中:http://openjdk.java.net/jeps/102

Based on Ashwin Jayaprakash s answer (+1) about the Apache 2.0 licensed SIGAR, here is how I use it to get only the PID of the current process:

import org.hyperic.sigar.Sigar;

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

尽管它不适用于所有平台,但它确实适用于Linux、Windows、OS X和此处列出的各种Unix平台

您可以在getpid()https://github.com/jnr/jnr-posix“rel=”nofollow“>JNR Posix

它有一个Windows POSIX包装器,可以从libc中调用getpid()。

我发现了一个可能有点边缘化的解决方案,我没有在Windows 10以外的其他操作系统上尝试过,但我认为这值得注意。

如果您发现自己在使用J2V8和nodejs,您可以运行一个简单的javascript函数,返回java进程的pid。

以下是一个示例:

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

这是我的解决方案:

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
");
                return true;
            }
        } catch (Exception e) {
            System.out.println("Exception:  " + e.getMessage());
        }
        return false;
    }




相关问题
热门标签