译自:How a Java Application Can Discover its Process ID (PID)
对于某些要与外部进程(非Java)协作的应用,通常需要获取到它自己的进程ID。但是当前的Java API并不提供接口以便直接检索PID(可能需要等到如下问题解决之后4250622、4244896、4890847)。
但是聪明的我还是找到五种从Java程序中获取PID的方法:
1.使用Java监控和管理的API(java.lang.management):
ManagementFactory.getRuntimeMXBean().getName();
得到数据类似: 28906@localhost
28906就是JVM进程ID,实际上也是当前应用的PID.
这一招是JVM直接支持的,但是我只在SUN自家的JVM测试过可行.
Java API中关于RuntimeMXBean.getName()方法的描述如下(来自Javadoc):
返回表示正在运行的 Java 虚拟机的名称。返回的名称字符串可以为任何任意字符串,Java 虚拟机实现可以选择在返回的名称字符串中嵌入特定于平台的有用信息。每个正在的运行的虚拟机可以具有不同的名称。
所以即使这个方法是最简便的,也可能因该方法的具体实现改变而导致你的应用无法正常运行.
2.通过shell脚本而非Java属性的方式来启动你的应用如下:
exec java -Dpid=$$ -jar /Applications/bsh-2.0b4.jar
然后在Java里调用这个:
System.getProperty("pid");
3.本博客使用shell脚本的$!设备描述符 - 如果你只是想要创建一个包含pid的文件,那这个方法挺方便~?
4.使用Java本地调用(JNI)- 一个灰常繁琐笨重且受限于平台的解决方案.
5.使用系统变量$PPID和Runtime.exec(String[])方法,在这篇文章中有详细描述.
import java.io.IOException; public class Pid { public static void main(String[] args) throws IOException { byte[] bo = new byte[100]; String[] cmd = {"bash", "-c", "echo $PPID"}; Process p = Runtime.getRuntime().exec(cmd); p.getInputStream().read(bo); System.out.println(new String(bo)); } }
可以说,以上的每一个方法都不好,各有优劣。(下面来一段作者的吐槽~_~)
我知道Sun的最高优先级是Java的跨平台兼容性,但我还是赞成下述在RFE中关于给JDK添加getPid()方法的留言:
求求你Sun,已经4、5年了~给我们PID,真的蒸的很需要,还有……可以一劳永逸的减少开发者们在文档里翻来覆去找寻这个莫须有的方法所浪费的时间~
P.S.
1.注意了,评论中有人说,在Unix系统下每次读取一个文件到内存里都会创建一个新的进程,所以每次运行
Process p = Runtime.getRuntime ().exec(cmd);都会得到一个不同的PID,这是再正常不过的~
2.关于第5点提及的文章中有详细解释:为什么不直接传一个字符串给exec执行呢?原因是Runtime.exec(String) does not parse quotes correctly的bug报告,该方法不能正确解析引号.
以上两点未经本人测试,参考的其他链接如下:
How to get the PID of the current JVM
ManagementFactory.getRuntimeMXBean().getName()
该方法返回的是“PID@HOST”,即当前运行JVM进程的ID和主机名。
JVM Management API
JDK5.0新特性系列---10.监控与管理虚拟机