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

如何获得我的Java进程的id ?

我知道有一些平台相关的黑客,但我更喜欢一个更通用的解决方案。

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

在linux+windows上,它返回类似"12345@hostname"的值(12345为进程id)。注意根据文件,这个值没有保证:

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

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

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

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

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

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

试试Sigar。非常广泛的api。Apache 2 license。

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

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

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

Java 9

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

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

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

下面的方法尝试从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>")

下面是一个后门方法,可能不适用于所有虚拟机,但应该适用于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);
这是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 repo获得tool.jar;用Maven配置它有点棘手
  • tool.jar可能包含平台相关的(本机?)代码,因此不容易 可分配的李< / >
  • 它在假设所有(本地)运行的JVM应用程序都是“可监控的”的情况下运行。它看起来像 从Java 6开始,所有应用程序通常(除非你主动配置相反)
  • 它可能只适用于Java 6+
  • Eclipse不发布主类,因此不容易获得Eclipse PID MonitoredVmUtil漏洞?李< / >

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

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

netstat -tupln | grep portNumber

基于Ashwin Jayaprakash的回答 (+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平台上工作。

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

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

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

自Java 9以来,有一个方法process . getpid(),它返回进程的本机ID:

public abstract class Process {


...


public long getPid();
}

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

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

以下是我的解决方案:

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

在Scala中:

import sys.process._
val pid: Long = Seq("sh", "-c", "echo $PPID").!!.trim.toLong
在Java 9发布之前,这应该给你一个在Unix系统上的解决方案。 (我知道,这个问题是关于Java的,但由于Scala没有相应的问题,所以我想把这个问题留给Scala用户,他们可能会遇到同样的问题。

为完整起见,在春天的引导中有一个包装器

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

我把这个加上其他解。

使用Java 10,来获得process id

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

我发现了一个可能有点极端的解决方案,除了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();
}