如何获取Java进程的ID?
我知道有几种与平台相关的黑客,但是我希望有一个更通用的解决方案。
不存在可以保证在所有jvm实现中都能工作的与平台无关的方式。
ManagementFactory.getRuntimeMXBean().getName()看起来是最好的(最近的)解决方案。它很短,可能在广泛使用的每个实现中都有效。
在linux + windows上,它返回类似12345@hostname的值(12345是进程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:
1
| long pid = ProcessHandle.current().pid(); |
您可以使用JNA。不幸的是,还没有通用的JNA API来获取当前的进程ID,但是每个平台都非常简单:
视窗
确保您有jna-platform.jar然后:
1
| int pid = Kernel32.INSTANCE.GetCurrentProcessId(); |
Unix系统
宣布:
1 2 3 4
| private interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);
int getpid ();
} |
然后:
1
| int pid = CLibrary.INSTANCE.getpid(); |
Java 9
在Java 9下,新的流程API可用于获取当前流程ID。首先,您要获取当前进程的句柄,然后查询PID:
1
| long pid = ProcessHandle.current().pid(); |
这是一种后门方法,该方法可能不适用于所有VM,但应同时在Linux和Windows上运行(此处为原始示例):
1 2 3 4 5 6 7 8 9 10 11
| 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许可证。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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("")。
对于较早的JVM,在Linux中...
1 2 3 4 5 6 7 8 9 10 11
| 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";
} |
您可以签出我的项目:GitHub上的JavaSysMon。它提供了进程ID和跨平台(目前为Windows,Mac OSX,Linux和Solaris)的其他功能(CPU使用率,内存使用率)
从Java 9开始,有一个Process.getPid()方法,该方法返回进程的本机ID:
1 2 3 4 5 6
| public abstract class Process {
...
public long getPid();
} |
要获取当前Java进程的进程ID,可以使用ProcessHandle接口:
1
| System.out.println(ProcessHandle.current().pid()); |
为了完整起见,Spring Boot中有一个包装器用于
1 2
| String jvmName = ManagementFactory.getRuntimeMXBean().getName();
return jvmName.split("@")[0]; |
解。如果需要一个整数,则可以将其汇总为一类:
1
| int pid = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]); |
如果某人已经使用过Spring Boot,则可能使用org.springframework.boot.ApplicationPid
1 2
| ApplicationPid pid = new ApplicationPid();
pid.toString(); |
toString()方法输出pid或'???'。
已经在其他答案中讨论了使用ManagementFactory的注意事项。
在Scala中:
1 2
| import sys.process._
val pid: Long = Seq("sh","-c","echo $PPID").!!.trim.toLong |
在应该发布Java 9之前,这应该为您提供在Unix系统上的解决方法。
(我知道,这个问题是关于Java的,但是由于Scala没有等效的问题,我想把这个问题留给可能偶然遇到相同问题的Scala用户。)
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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;
} |
1
| java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0] |
我发现的最新消息是,至少在linux上有一个名为sun.java.launcher.pid的系统属性。我的计划是使用它,如果未发现使用JMX bean。
这取决于您从哪里寻找信息。
如果要从控制台查找信息,则可以使用jps命令。该命令给出的输出类似于Unix ps命令,并且随JDK一起提供,因为我相信1.5
如果您从流程中查找,则RuntimeMXBean(如Wouter Coekaerts所说)可能是您的最佳选择。 Windows上使用Sun JDK 1.6 u7的getName()的输出格式为[PROCESS_ID] @ [MACHINE_NAME]。但是,您可以尝试执行jps并从中解析结果:
1 2
| String jps = [JDK HOME] +"\\bin\\jps.exe";
Process p = Runtime.getRuntime().exec(jps); |
如果不带任何选项运行,则输出应为进程ID,后跟名称。
根据Ashwin Jayaprakash的回答(+1)
关于Apache 2.0许可的SIGAR,这是我使用它仅获取当前进程的PID的方式:
1 2 3 4 5
| import org.hyperic.sigar.Sigar;
Sigar sigar = new Sigar();
long pid = sigar.getPid();
sigar.close(); |
即使它不适用于所有平台,也可以在Linux,Windows,OS X和此处列出的各种Unix平台上工作。
这是代码JConsole,并且可能是jps和VisualVM使用。它利用了
sun.jvmstat.monitor.*软件包,来自tool.jar。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| 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中的错误?
更新:我刚刚仔细检查过JPS是否使用这种方式,即Jvmstat库(tool.jar的一部分)。因此,无需像外部示例一样将JPS称为外部进程,而直接调用Jvmstat库。您可以通过这种方式在本地运行的所有JVM列表。
请参阅JPS源代码:
我发现了一个可能有点过时的解决方案,并且没有在Windows 10以外的其他操作系统上尝试过,但是我认为这是值得注意的。
如果您发现自己正在使用J2V8和nodejs,则可以运行一个简单的javascript函数,以返回Java进程的pid。
这是一个例子:
1 2 3 4 5 6 7
| public static void main(String[] args) {
NodeJS nodeJS = NodeJS.createNodeJS();
int pid = nodeJS.getRuntime().executeIntegerScript("process.pid;
");
System.out.println(pid);
nodeJS.release();
} |
您可以在JNR-Posix中尝试getpid()。
它具有Windows POSIX包装器,该包装器从libc调用getpid()。
我知道这是一个旧线程,但我想指出的是,用于获取PID的API(以及运行时对Java进程的其他操作)已添加到JDK 9中的Process类中:http:// openjdk。 java.net/jeps/102
添加到其他解决方案。
使用Java 10获得process id
1 2 3
| final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
final long pid = runtime.getPid();
out.println("Process ID is '" + pid); |
这是我的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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;
} |
这是我有类似要求时使用的。这样可以正确确定Java进程的PID。让您的Java代码在预定义的端口号上生成服务器,然后执行OS命令以找出侦听该端口的PID。对于Linux
1
| netstat -tupln | grep portNumber |