387

如何获取我的 Java 进程的 ID?

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

4

22 回答 22

383

不存在可以保证在所有 jvm 实现中工作的独立于平台的方式。 ManagementFactory.getRuntimeMXBean().getName()看起来是最好的(最接近的)解决方案,通常包括 PID。它很短,并且可能适用于广泛使用的每个实现。

在 linux+windows 上,它返回一个值,例如"12345@hostname"12345作为进程 ID)。请注意,尽管根据文档,对此值没有任何保证:

返回代表正在运行的 Java 虚拟机的名称。返回的名称字符串可以是任意字符串,Java 虚拟机实现可以选择在返回的名称字符串中嵌入特定于平台的有用信息。每个正在运行的虚拟机可以有不同的名称。

在 Java 9中,可以使用新的流程 API :

long pid = ProcessHandle.current().pid();
于 2008-08-30T11:11:17.277 回答
125

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

视窗

确保你有jna-platform.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();

爪哇 9

在 Java 9 下,新的进程 API可用于获取当前进程 ID。首先获取当前进程的句柄,然后查询 PID:

long pid = ProcessHandle.current().pid();
于 2011-09-05T02:33:57.293 回答
63

这是一个后门方法,它可能不适用于所有虚拟机,但应该适用于 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);
于 2012-08-22T05:19:41.507 回答
36

试试西格。非常广泛的 API。阿帕奇 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();
}
于 2010-06-28T18:09:17.320 回答
28

以下方法尝试从中提取 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>")

于 2011-10-07T16:32:52.800 回答
25

对于较旧的 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";
}
于 2011-06-16T12:56:19.173 回答
19

从 Java 9 开始,有一个方法 Process.getPid() 返回进程的本地 ID:

public abstract class Process {

    ...

    public long getPid();
}

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

System.out.println(ProcessHandle.current().pid());
于 2015-06-26T11:56:20.053 回答
18

你可以查看我的项目: GitHub 上的JavaSysMon。它提供进程 ID 和一堆其他东西(CPU 使用率、内存使用率)跨平台(目前是 Windows、Mac OSX、Linux 和 Solaris)

于 2009-12-26T00:44:59.740 回答
10

在斯卡拉:

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

在 Java 9 发布之前,这应该会为您提供 Unix 系统上的解决方法。(我知道,这个问题是关于 Java 的,但是由于 Scala 没有等效的问题,我想把这个留给可能遇到同样问题的 Scala 用户。)

于 2015-11-20T23:32:12.827 回答
10
java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]
于 2017-04-13T19:09:59.480 回答
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 的注意事项已经在其他答案中讨论过。

于 2016-06-30T12:20:49.280 回答
7
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;
}
于 2016-09-28T10:14:19.307 回答
6

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

使用 Java 10,获得process id

final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
final long pid = runtime.getPid();
out.println("Process ID is '" + pid);
于 2018-02-24T03:50:10.567 回答
5

我发现的最新消息是至少在 linux 上可以使用一个名为的系统属性。sun.java.launcher.pid我的计划是使用它,如果没有找到使用JMX bean.

于 2011-09-05T13:47:41.443 回答
4

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

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

如果您从流程来看,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 后跟名称。

于 2008-09-04T01:07:49.930 回答
4

这是 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 回购中获得;用 Maven 配置它有点棘手
  • 可能包含平台相关(本tool.jar机?)代码,因此不容易分发
  • 它的运行假设所有(本地)运行的 JVM 应用程序都是“可监控的”。看起来从 Java 6 开始,所有应用程序通常都是(除非您主动配置相反)
  • 它可能仅适用于 Java 6+
  • Eclipse不发布主类,所以不会轻易获取Eclipse PID MonitoredVmUtil中的Bug?

更新:我刚刚仔细检查了 JPS 使用这种方式,即 Jvmstat 库(tool.jar 的一部分)。所以不需要将JPS作为外部进程调用,直接调用Jvmstat库,如我的示例所示。您还可以通过这种方式获取在 localhost 上运行的所有 JVM 的列表。请参阅 JPS源代码

于 2013-06-27T16:28:17.887 回答
2

根据 Ashwin Jayaprakash对 Apache 2.0 许可的回答SIGAR(+1) ,以下是我如何使用它来仅获取当前进程的 PID:

import org.hyperic.sigar.Sigar;

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

尽管它不能在所有平台上运行,但它可以在Linux、Windows、OS X 和此处列出的各种 Unix 平台上运行

于 2014-02-11T12:47:46.457 回答
2

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

于 2015-06-24T21:07:30.347 回答
1

getpid()您可以在JNR-Posix中尝试。

它有一个从 libc 调用 getpid() 的 Windows POSIX 包装器。

于 2015-03-11T08:15:33.360 回答
1

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

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

这是一个例子:

public static void main(String[] args) {
    NodeJS nodeJS = NodeJS.createNodeJS();
    int pid = nodeJS.getRuntime().executeIntegerScript("process.pid;\n");
    System.out.println(pid);
    nodeJS.release();
}
于 2018-09-01T17:57:41.237 回答
-1

这是我的解决方案:

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;
    }
于 2015-11-06T19:10:09.243 回答
-6

这是我有类似要求时使用的。这将正确确定 Java 进程的 PID。让您的 java 代码在预定义的端口号上生成服务器,然后执行操作系统命令以找出侦听端口的 PID。对于 Linux

netstat -tupln | grep portNumber
于 2013-09-30T09:42:13.883 回答