题
如何获取我的 Java 进程的 ID?
我知道有几种依赖于平台的技巧,但我更喜欢更通用的解决方案。
解决方案
不存在可以保证在所有 jvm 实现中工作的独立于平台的方法。ManagementFactory.getRuntimeMXBean().getName()
看起来是最好的(最接近的)解决方案。它很短,而且 大概 适用于广泛使用的每个实现。
在 linux+windows 上它返回一个类似的值 12345@hostname
(12345
是进程 ID)。但要小心 根据文档, ,对此值没有任何保证:
返回代表正在运行的 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();
这是一个后门方法 可能 不适用于所有虚拟机,但应该适用于 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);
尝试 西加尔 。非常广泛的 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();
}
以下方法尝试从中提取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>")
, , 例如。
对于较旧的 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";
}
你可以看看我的项目: JavaSysMon 在 GitHub 上。它提供进程 ID 和一堆其他跨平台信息(CPU 使用情况、内存使用情况)(目前为 Windows、Mac OSX、Linux 和 Solaris)
从 Java 9 开始,有一个 Process.getPid() 方法可以返回进程的本机 ID:
public abstract class Process {
...
public long getPid();
}
要获取当前 Java 进程的进程 ID,可以使用 ProcessHandle
界面:
System.out.println(ProcessHandle.current().pid());
在斯卡拉中:
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;
}
我最新发现的是有一个 系统属性 被称为 sun.java.launcher.pid
至少在linux上是可用的。我的计划是使用它,如果没有找到,则使用 JMX bean
.
java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]
这取决于您从哪里查找信息。
如果您要从控制台查找信息,可以使用 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 的 回答 (+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 平台.
这是 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不发布主类,因此您不会在MonitoredVMutil中轻松地获得Eclipse PID?
更新:我刚刚仔细检查过 JPS 使用这种方式,即 Jvmstat 库(tool.jar 的一部分)。所以不需要调用JPS作为外部进程,直接调用Jvmstat库,如我的示例所示。您还可以通过这种方式获取在本地主机上运行的所有 JVM 的列表。参见 JPS 源代码:
你可以试试 getpid()
在 JNR-Posix.
它有一个 Windows POSIX 包装器,可以调用 libc 的 getpid() 。
我知道这是一个旧线程,但我想指出用于获取 PID(以及运行时 Java 进程的其他操作)的 API 已添加到 JDK 9 中的 Process 类中: http://openjdk.java.net/jeps/102
我发现了一个可能有点边缘情况的解决方案,并且我没有在 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();
}
添加到其他解决方案。
使用 Java 10,得到 process id
final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
final long pid = runtime.getPid();
out.println("Process ID is '" + 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;
}
这是我有类似需求时使用的。这正确地确定了Java进程的PID。让您的 java 代码在预定义的端口号上生成一个服务器,然后执行操作系统命令以找出侦听该端口的 PID。对于Linux
netstat -tupln | grep portNumber