Java程序如何获得自己的进程ID?
我如何获得我的Java过程的ID? 我知道有几个平台依赖的黑客,但我更喜欢更通用的解决scheme。
没有平台无关的方式可以保证在所有的jvm实现中工作。 ManagementFactory.getRuntimeMXBean().getName()
看起来像最好的(最接近的)解决scheme。 它很短, 可能适用于广泛使用的各种实施。
在linux + windows上,它返回一个值,如12345@hostname
( 12345
是进程ID)。 根据文档要小心,这个值没有保证:
返回表示正在运行的Java虚拟机的名称。 返回的名称string可以是任意的string,Java虚拟机实现可以select将特定于平台的有用信息embedded到返回的名称string中。 每个正在运行的虚拟机可以有不同的名称。
在Java 9中 ,可以使用新的进程API :
long pid = ProcessHandle.current().getPid();
你可以使用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().getPid();
这里有一个后门的方法, 可能不适用于所有的虚拟机,但应该在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>")
。
你可以看看我的项目:在GitHub上的JavaSysMon 。 它提供了进程ID和一堆其他东西(CPU使用情况,内存使用情况)跨平台(目前是Windows,Mac OSX,Linux和Solaris)
对于较旧的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().getPid());
最近我发现有一个名为sun.java.launcher.pid
的系统属性 ,至less在linux上是可用的。 我的计划是使用它,如果没有发现使用JMX bean
。
这取决于你在哪里寻找信息。
如果您正在从控制台查找信息,则可以使用jps命令。 该命令给出的输出类似于Unix的ps命令,并且由于我相信1.5而带有JDK
如果您正在从stream程中寻找RuntimeMXBean(如Wouter Coekaerts所说),可能是您的最佳select。 使用Sun JDK 1.6 u7的Windows上getName()的输出格式为[PROCESS_ID] @ [MACHINE_NAME]。 你可以尝试执行jps并parsing结果:
String jps = [JDK HOME] + "\\bin\\jps.exe"; Process p = Runtime.getRuntime().exec(jps);
如果在没有选项的情况下运行,则输出应该是进程标识,后跟名称。
在Scala中:
import sys.process._ val pid: Long = Seq("sh", "-c", "echo $PPID").!!.trim.toLong
这应该会给你一个解决Unix系统的问题,直到Java 9发布。 (我知道,问题是关于Java,但是因为对于Scala没有相同的问题,所以我想把这个留给那些可能碰到同样问题的Scala用户。)
为了完整性, Spring Boot中有一个包装器
String jvmName = ManagementFactory.getRuntimeMXBean().getName(); return jvmName.split("@")[0];
解。 如果需要一个整数,那么这可以归结为一行:
int pid = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
如果某人已经使用Spring引导,她/他可能会使用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; }
基于Ashwin Jayaprakash关于Apache 2.0许可SIGAR
的回答 (+1),以下是我如何使用它来获取当前进程的PID:
import org.hyperic.sigar.Sigar; Sigar sigar = new Sigar(); long pid = sigar.getPid(); sigar.close();
尽pipe它不适用于所有平台,但它在Linux,Windows,OS X以及这里列出的各种Unix平台上都能正常工作。
java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]
这是JConsole代码,可能是jps和VisualVM使用的。 它利用来自sun.jvmstat.monitor.*
包中的类。
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
获取tool.jar
; 用Mavenconfiguration它有点棘手 -
tool.jar
可能包含依赖于平台的(native?)代码,因此不容易分发 - 它假设所有(本地)正在运行的JVM应用程序都是“可监视的”。 看起来来自Java 6的所有应用程序通常都是(除非您主动configuration相反)
- 它可能只适用于Java 6+
- Eclipse不发布主类,所以你不会轻易获得Eclipse PID MonitoredVmUtil中的错误?
更新:我刚刚检查了JPS使用这种方式,这是Jvmstat库(tool.jar的一部分)。 所以没有必要把JPS作为外部进程调用,直接调用Jvmstat库就如我的例子所示。 您可以通过这种方式获取本地主机上运行的所有JVM的列表。 查看JPS 源代码 :
您可以在JNR-Posix中尝试getpid()
。
它有一个Windows的POSIX包装,它调用了libc的getpid()。
我知道这是一个古老的线程,但是我想要调用API来获取PID(以及在运行时对Java进程的其他操作)正被添加到JDK 9中的Process类: http:// openjdk。 java.net/jeps/102
这是我的解决scheme:
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