繁体   English   中英

"Java 程序如何获得自己的进程 ID?"

[英]How can a Java program get its own process ID?

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

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

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

在 linux+windows 上,它返回一个类似12345@hostname的值( 12345是进程 ID)。 请注意, 根据 docs ,无法保证此值:

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

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

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

你可以使用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();

这是一个后门方法,它可能不适用于所有 VM,但应该适用于 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();
}

以下方法尝试从java.lang.management.ManagementFactory提取 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());

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

在斯卡拉:

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

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

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

java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]
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;
}

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

使用 Java 10,获取process id

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

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

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

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

这取决于您从何处查找信息。

如果要从控制台查找信息,可以使用 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 后跟名称。

基于 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 平台

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

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

它有一个 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;\n");
    System.out.println(pid);
    nodeJS.release();
}

在此处输入图像描述<\/a>

这适用于:OpenJDK 运行时环境 Corretto-8.302.08.1(内部版本 1.8.0_302-b08) OpenJDK 64 位服务器 VM Corretto-8.302.08.1(内部版本 25.302-b08,混合模式)

这是我的解决方案:

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

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

netstat -tupln | grep portNumber

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM