如何获取我刚刚在java程序中启动的进程的PID?
我已经使用以下代码启动了一个进程
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "path");
try {
Process p = pb.start();
}
catch (IOException ex) {}
现在我需要知道我刚刚启动的进程的 pid。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
一种解决方案是使用平台提供的特殊工具:
免责声明:未经测试,但您明白了:
ps
列出进程,ps
列出它。One solution is to use the idiosyncratic tools the platform offers:
Disclaimer: Not tested, but you get the idea:
ps
to list the processes,ps
too.对于 GNU/Linux 和MacOS(或通常类似 UNIX)系统,我使用了以下方法,效果很好:
For GNU/Linux & MacOS (or generally UNIX like) systems, I've used below method which works fine:
我为那些仍然坚持使用 Java 8 的人做了一个快速而肮脏的解决方案,
我希望您发现这个片段有用。
I made a quick and dirty solution for those who are still stuck with Java 8
I hope you find this snippet useful.
由于Java 9类
Process
有新方法long pid()
,所以就这么简单Since Java 9 class
Process
has new methodlong pid()
, so it is as simple as目前还没有可用的公共 API。请参阅 Sun Bug 4244896,Sun Bug 4250622
作为解决方法:
返回类型的对象
Process 类是抽象的,您将得到什么是为您的操作系统设计的 Process 的一些子类。例如,在 Mac 上,它返回 java.lang.UnixProcess ,其中有一个名为 pid 的私有字段。使用Reflection您可以轻松获取该字段的值。这无疑是一种黑客行为,但可能会有所帮助。您到底需要
PID
做什么?There is no public API for this yet. see Sun Bug 4244896, Sun Bug 4250622
As a workaround:
returns an Object of type
The Process class is abstract, and what you get back is some subclass of Process which is designed for your operating system. For example on Macs, it returns
java.lang.UnixProcess
which has a private field calledpid
. Using Reflection you can easily get the value of this field. This is admittedly a hack, but it might help. What do you need thePID
for anyway?在 Unix 系统(Linux 和 Mac)中
In Unix System (Linux & Mac)
此页面有 HOWTO:
http://www.golesny.de/p/code/javagetpid
在 Windows 上:
返回“java.lang.Win32Process”的实例或“java.lang.ProcessImpl”
两者都有一个私有字段“handle”。
这是该进程的操作系统句柄。您必须使用此 + Win32 API 来查询 PID。该页面详细介绍了如何执行此操作。
This page has the HOWTO:
http://www.golesny.de/p/code/javagetpid
On Windows:
Returns an instance of "java.lang.Win32Process") OR "java.lang.ProcessImpl"
Both have a private field "handle".
This is an OS handle for the process. You will have to use this + Win32 API to query PID. That page has details on how to do that.
在您的库中包含 jna (“JNA”和“JNA Platform”)并使用此功能:
您还可以从此处下载JNA和JNA来自此处的平台。
Include jna (both "JNA" and "JNA Platform") in your library and use this function:
You can also download JNA from here and JNA Platform from here.
我想我已经找到了一个解决方案,在大多数平台上工作时看起来都非常安全。
想法如下:
由于您仅检查子进程,因此您不会被同一台计算机中的其他进程所错误。 JVM 范围的互斥体可以让您确定新进程是正确的。
读取子进程列表比从进程对象获取PID更简单,因为它不需要Windows上的WIN API调用,更重要的是,它已经在几个库中完成了。
下面是使用 JavaSysMon 库实现上述想法。它
I think I have found out a solution, that looks quite bulletproof while working on most platforms.
Here is the idea:
Since you check only for child processes, you cannot be wronged by some other process in the same machine. JVM-wide mutex than allows you to be sure, that the new process is the correct one.
Reading child process list is simpler than getting PID from process objects, because it does not require WIN API calls on windows, and, more importantly, it has been done already in several libs.
Below is an implementation of the above idea using JavaSysMon library. It
在我的测试中,所有 IMPL 类都有“pid”字段。这对我有用:
只需确保返回值不是-1。如果是,则解析 ps 的输出。
In my testing all IMPL classes had the field "pid". This has worked for me:
Just make sure the returned value is not -1. If it is, then parse the output of
ps
.我使用了一种不可移植的方法从
Process
对象中检索 UNIX PID,该方法非常容易遵循。第 1 步:
使用一些反射 API 调用来识别目标服务器 JRE 上的 Process 实现类(请记住,Process 是一个抽象类)。如果您的 UNIX 实现与我的一样,您将看到一个实现类,它有一个名为
pid
的属性,其中包含进程的 PID。这是我使用的日志记录代码。第 2 步:
根据从反射日志记录中获取的实现类和字段名称,编写一些代码来窃取
Process
实现类并使用反射 API 从中检索 PID。下面的代码适用于我的 UNIX 风格。您可能需要调整EXPECTED_IMPL_CLASS_NAME
和EXPECTED_PID_FIELD_NAME
常量才能使其适合您。I used a non-portable approach to retrieve the UNIX PID from the
Process
object that is very simple to follow.STEP 1:
Use some Reflection API calls to identify the
Process
implementation class on the target server JRE (remember thatProcess
is an abstract class). If your UNIX implementation is like mine, you will see an implementation class that has a property namedpid
that contains the PID of the process. Here is the logging code that I used.STEP 2:
Based on the implementation class and field name that you obtained from the Reflection logging, write some code to pickpocket the
Process
implementation class and retrieve the PID from it using the Reflection API. The code below works for me on my flavour of UNIX. You may have to adjust theEXPECTED_IMPL_CLASS_NAME
andEXPECTED_PID_FIELD_NAME
constants to make it work for you.这不是一个通用的答案。
但是:某些程序,尤其是服务和长时间运行的程序,会创建(或主动提供创建,可选)“pid 文件”。
例如,LibreOffice 提供
--pidfile={file}
,请参阅 文档。我花了很长时间寻找 Java/Linux 解决方案,但 PID(就我而言)就在手边。
This is not a generic answer.
However: Some programs, especially services and long-running programs, create (or offer to create, optionally) a "pid file".
For instance, LibreOffice offers
--pidfile={file}
, see the docs.I was looking for quite some time for a Java/Linux solution but the PID was (in my case) lying at hand.
使用JNA,支持新旧JVM获取进程id
Using JNA, supporting old and new JVM to get process id
没有一个简单的解决方案。我过去的做法是启动另一个进程,在类 Unix 系统上运行
ps
命令,或者在 Windows 上运行tasklist
命令,然后解析该命令的输出以获得我想要的 PID。实际上,我最终将该代码放入每个平台的单独 shell 脚本中,该脚本仅返回 PID,这样我就可以使 Java 部分尽可能保持平台独立。这对于短期任务来说效果不佳,但这对我来说不是问题。There isn't a simple solution. The way I've done it in the past is to start another process to run either the
ps
command on Unix-like systems, or thetasklist
command on Windows, and then parse the output of that command for the PID I want. In reality, I ended up putting that code into a separate shell script for each platform which just returned the PID, so that I could keep the Java piece as platform independent as possible. This doesn't work well for short-lived tasks, but that wasn't an issue for me.jnr-process 项目提供了此功能。
它是 jruby 使用的 java 本机运行时的一部分,可以被视为未来 java-FFI
the jnr-process project provides this capability.
It is part of the java native runtime used by jruby and can be considered a prototype for a future java-FFI
我相信唯一可移植的方法是通过另一个(父)Java 进程运行(子)进程,这将告诉我父进程的实际 PID。子进程可以是任何东西。
该包装器的代码是
要使用它,请仅使用此文件创建一个 jar 文件,并使用以下命令参数调用它:
I believe the only portable way to do this, is to run a (child) process through another (parent) Java process, which will inform me the actual PID of the parent process. The child process could be anything.
The code of this wrapper is
To use it, create a jar file with just this one, and call it with command arguments this:
如果可移植性不是问题,并且您只想在 Windows 上轻松获取 pid,同时使用经过测试且已知可在所有现代版本的 Windows 上运行的代码,则可以使用 kohsuke 的 winp 库。它也可以在 Maven Central 上使用,以方便使用。
If portability is not a concern, and you just want to get the pid on Windows without a lot of hassle while using code that is tested and known to work on all modern versions of Windows, you can use kohsuke's winp library. It is also available on Maven Central for easy consumption.
有一个开源库具有这样的功能,并且它具有跨平台实现: https ://github.com/OpenHFT/Java-Thread-Affinity
仅仅获取 PID 可能有点过分了,但是如果你想要其他东西,比如 CPU 和线程 id,特别是线程亲和力,它可能就足够了你。
要获取当前线程的 PID,只需调用
Affinity.getAffinityImpl().getProcessId()
。这是使用 JNA 实现的(参见 arcsin 的答案)。
There is an open-source library that has such a function, and it has cross-platform implementations: https://github.com/OpenHFT/Java-Thread-Affinity
It may be overkill just to get the PID, but if you want other things like CPU and thread id, and specifically thread affinity, it may be adequate for you.
To get the current thread's PID, just call
Affinity.getAffinityImpl().getProcessId()
.This is implemented using JNA (see arcsin's answer).