如何找到在Java中启动的进程的进程ID(PID)?

22

如果我在Java中通过 Runtime.getRuntime().exec(...) 或者 ProcessBuilder.start() 获取了一个进程对象,我可以通过 Process.waitFor() 等待它,就像 Thread.join() 一样,或者可以使用 Process.destroy() 来结束它,就像已被弃用的 Thread.stop() 方法。

但问题是:如何找到进程对象的pid?在官方文档中没有看到这样的方法。 我能在Java中做到吗? 如果可以,怎么做?

5个回答

11

这个人呼叫bash获取PID。我不确定是否有Java解决方案。

/**
 * Gets a string representing the pid of this program - Java VM
 */
public static String getPid() throws IOException,InterruptedException {

  Vector<String> commands=new Vector<String>();
  commands.add("/bin/bash");
  commands.add("-c");
  commands.add("echo $PPID");
  ProcessBuilder pb=new ProcessBuilder(commands);

  Process pr=pb.start();
  pr.waitFor();
  if (pr.exitValue()==0) {
    BufferedReader outReader=new BufferedReader(new InputStreamReader(pr.getInputStream()));
    return outReader.readLine().trim();
  } else {
    System.out.println("Error while getting PID");
    return "";
  }
}

Source: http://www.coderanch.com/t/109334/Linux-UNIX/UNIX-process-ID-java-program


我认为这将给出JVM进程的pid...而不是Java生成的进程,我相信这就是问题所问的。 - splashout
我认为你需要更仔细地阅读。它会生成一个进程,其唯一的工作是将其自己的PID回显到其stdout,这本身正在管道传输到与JVM关联的stdin文件描述符。 - nsfyn55
向量已经过时了,并且是同步的 - 没有真正需要使用那种类型的集合 - 尝试使用 ArrayList 代替。只是说一下。 - KRK Owner
只是在说什么?这与问题无关。问题是关于访问PID而不是Java最佳实践。 - nsfyn55

7

与其他提到的工具类似,Java运行时自带了jps命令行工具。它会输出所有正在运行的JVM的PID。好处是需要解析的输出仅限于JVM进程。


另一个好处是:它是跨平台的,不像tasklist。 - Mike Baranczak

0

我遇到了和你一样的问题。我找到了一个相当不错的解决方案,我建议在它启动之前稍微休眠一下,以确保进程已经正式启动。

Process p = Runtime.getRuntime().exec("cmd /c tasklist");
StringWriter writer = new StringWriter();
IOUtils.copy(p.getInputStream(), writer);
String theString = writer.toString();
//System.out.println(theString);
id = findLastString("javaw.exe                     .{1,} Console                    1", theString);
System.out.println(id);

其中findLastString被定义为

public static String findLastString(String pattern, String in) {
     Pattern p = Pattern.compile(pattern);
     Matcher matcher = p.matcher(in);
     String it= "";
     while(matcher.find()) {
       it = matcher.group();
       try {
        Thread.sleep(10);
       } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
       }
     }
     int firstIndex=pattern.indexOf(".{1,}");
     int lastIndex=it.substring(firstIndex).indexOf(pattern.substring(pattern.indexOf(".{1,}")+5))+firstIndex;
     String dotOn = it.substring(pattern.indexOf(".{1,}"));

     it=it.substring(firstIndex, lastIndex);
     return it;
 }

基本上,这将获取正在运行的进程列表,并查找最近运行的一个,其中,在此示例中,名称为javaw.exe(我的程序正在启动一个单独的java进程)。您可以用任务管理器找到进程的名称来替换javaw.exe。您还需要获取Apache common IO jar。

0
Leo,经过我自己大约一周的研究后,我认为Jhurtado的方法可能是我们现在在Java中能够实现的“最佳”方法。这里的“最佳”用引号括起来是因为它有一个非常恶劣的副作用,基本上是对你的子PID进行“猜测”。
如果您的Java应用程序在高负载系统中快速生成本地进程,则无法保证您在差异计算中捕获的PID是当前线程启动的进程的PID,或者您选择的进程的PID甚至是由我们的应用程序生成的(也许主机系统已经运行了该进程)。
话虽如此,如果您没有生成数十个进程或者您生成的本地进程非常独特(某些您随应用程序提供的自定义工具),那么这种方法就可以正常工作,在这种情况下,您要查找的本地进程的PID就是您想要的PID。
在Windows上,您可以像Jhurtado指出的那样使用“tasklist”获取完整的PID列表,并过滤出您想要的PID(在我的测试中,使用/FI筛选器开关没有起作用)。
在任何*nix系统上,您可以使用“ps ax | grep ”,其中NAME是您想要过滤的某个进程名称,例如'nginx'或'httpd',以获取列表。
此外,如果您需要终止杂散进程(例如,在VM退出时)*nix上,您当然可以使用“kill -9 ”,在Windows上,有趣的是,您可以使用'taskkill '。
不幸的是,这几乎不是最佳选择。

-2

我认为在Java中,您最好在生成子进程之前和之后获取tasklist。执行差异并获取PID。

您可以通过发出Runtime.getRuntime.exec("tasklist");来获取Tasklist。
请注意,tasklist.exe不包含在Windows XP Home版中,但仍然可以下载它。


你假设我在使用Windows,但事实并非如此。 - Leo Izen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接