如何获得我刚刚在java程序中启动的进程的PID?

raf*_*raf 66 java pid process processbuilder

我已经开始使用以下代码进行处理

 ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "path");
 try {
     Process p = pb.start();       
 } 
 catch (IOException ex) {}
Run Code Online (Sandbox Code Playgroud)

现在我需要知道我刚刚开始的进程的pid.

Ami*_*ani 25

目前还没有公共API.见Sun Bug 4244896,Sun Bug 4250622

作为解决方法:

Runtime.exec(...)
Run Code Online (Sandbox Code Playgroud)

返回一个类型的Object

java.lang.Process
Run Code Online (Sandbox Code Playgroud)

Process类是抽象的,你得到的是Process的一些子类,它是为你的操作系统设计的.例如,在Mac上,它返回java.lang.UnixProcess有一个名为的私有字段pid.使用Reflection,您可以轻松获得此字段的值.这无疑是一个黑客,但它可能会有所帮助.PID无论如何你还需要什么?

  • 在Windows上,它返回java.lang.ProcessImpl,它没有PID的概念.不幸的是,您的解决方案并非跨平台. (11认同)

Sha*_*rma 24

这个页面有HOWTO:

http://www.golesny.de/p/code/javagetpid

在Windows上:

Runtime.exec(..)
Run Code Online (Sandbox Code Playgroud)

返回"java.lang.Win32Process")或"java.lang.ProcessImpl"的实例

两者都有一个私人领域"句柄".

这是该过程的OS句柄.您将不得不使用此+ Win32 API来查询PID.该页面详细介绍了如何执行此操作.


cze*_*rny 24

由于Java 9Process有新方法long pid(),所以就这么简单

ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "path");
try {
    Process p = pb.start();
    long pid = p.pid();      
} catch (IOException ex) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)


LRB*_*H10 19

在Unix系统(Linux和Mac)

 public static synchronized long getPidOfProcess(Process p) {
    long pid = -1;

    try {
      if (p.getClass().getName().equals("java.lang.UNIXProcess")) {
        Field f = p.getClass().getDeclaredField("pid");
        f.setAccessible(true);
        pid = f.getLong(p);
        f.setAccessible(false);
      }
    } catch (Exception e) {
      pid = -1;
    }
    return pid;
  }
Run Code Online (Sandbox Code Playgroud)

  • @idelvall 你想在这里实现线程安全吗?Pid是最终的,读取它的值是安全的。 (2认同)

arc*_*sin 14

在库中包含jna("JNA"和"JNA平台")并使用此功能:

import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT;
import java.lang.reflect.Field;

public static long getProcessID(Process p)
    {
        long result = -1;
        try
        {
            //for windows
            if (p.getClass().getName().equals("java.lang.Win32Process") ||
                   p.getClass().getName().equals("java.lang.ProcessImpl")) 
            {
                Field f = p.getClass().getDeclaredField("handle");
                f.setAccessible(true);              
                long handl = f.getLong(p);
                Kernel32 kernel = Kernel32.INSTANCE;
                WinNT.HANDLE hand = new WinNT.HANDLE();
                hand.setPointer(Pointer.createConstant(handl));
                result = kernel.GetProcessId(hand);
                f.setAccessible(false);
            }
            //for unix based operating systems
            else if (p.getClass().getName().equals("java.lang.UNIXProcess")) 
            {
                Field f = p.getClass().getDeclaredField("pid");
                f.setAccessible(true);
                result = f.getLong(p);
                f.setAccessible(false);
            }
        }
        catch(Exception ex)
        {
            result = -1;
        }
        return result;
    }
Run Code Online (Sandbox Code Playgroud)

您也可以从这里下载JNA 这里和JNA的平台,在这里.


Mar*_*rák 8

我想我找到了一个解决方案,在大多数平台上工作时看起来非常防弹.这是一个想法:

  1. 创建在生成新进程/终止进程之前获取的JVM范围的互斥锁
  2. 使用与平台相关的代码来获取JVM进程的子进程列表+ pids
  3. 产生新的过程
  4. 获取子进程+ pid的新列表,并与之前的列表进行比较.新的是你的家伙.

由于您只检查子进程,因此不能被同一台计算机中的某些其他进程所冤枉.JVM范围的互斥锁比允许您确定新进程是正确的.

读取子进程列表比从进程对象获取PID更简单,因为它不需要在Windows上进行WIN API调用,更重要的是,它已经在几个库中完成了.

下面是使用JavaSysMon库实现上述想法.它

class UDKSpawner {

    private int uccPid;
    private Logger uccLog;

    /**
     * Mutex that forces only one child process to be spawned at a time. 
     * 
     */
    private static final Object spawnProcessMutex = new Object();

    /**
     * Spawns a new UDK process and sets {@link #uccPid} to it's PID. To work correctly,
     * the code relies on the fact that no other method in this JVM runs UDK processes and
     * that no method kills a process unless it acquires lock on spawnProcessMutex.
     * @param procBuilder
     * @return 
     */
    private Process spawnUDK(ProcessBuilder procBuilder) throws IOException {
        synchronized (spawnProcessMutex){            
            JavaSysMon monitor = new JavaSysMon();
            DirectUDKChildProcessVisitor beforeVisitor = new DirectUDKChildProcessVisitor();
            monitor.visitProcessTree(monitor.currentPid(), beforeVisitor);
            Set<Integer> alreadySpawnedProcesses = beforeVisitor.getUdkPids();

            Process proc = procBuilder.start();

            DirectUDKChildProcessVisitor afterVisitor = new DirectUDKChildProcessVisitor();
            monitor.visitProcessTree(monitor.currentPid(), afterVisitor);
            Set<Integer> newProcesses = afterVisitor.getUdkPids();

            newProcesses.removeAll(alreadySpawnedProcesses);

            if(newProcesses.isEmpty()){
                uccLog.severe("There is no new UKD PID.");
            }
            else if(newProcesses.size() > 1){
                uccLog.severe("Multiple new candidate UDK PIDs");
            } else {
                uccPid = newProcesses.iterator().next();
            }
            return proc;
        }
    }    

    private void killUDKByPID(){
        if(uccPid < 0){
            uccLog.severe("Cannot kill UCC by PID. PID not set.");
            return;
        }
        synchronized(spawnProcessMutex){
            JavaSysMon monitor = new JavaSysMon();
            monitor.killProcessTree(uccPid, false);
        }
    }

    private static class DirectUDKChildProcessVisitor implements ProcessVisitor {
        Set<Integer> udkPids = new HashSet<Integer>();

        @Override
        public boolean visit(OsProcess op, int i) {
            if(op.processInfo().getName().equals("UDK.exe")){
                udkPids.add(op.processInfo().getPid());
            }
            return false;
        }

        public Set<Integer> getUdkPids() {
            return udkPids;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Jar*_*ler 5

在我的测试中,所有 IMPL 类都有“pid”字段。这对我有用:

public static int getPid(Process process) {
    try {
        Class<?> cProcessImpl = process.getClass();
        Field fPid = cProcessImpl.getDeclaredField("pid");
        if (!fPid.isAccessible()) {
            fPid.setAccessible(true);
        }
        return fPid.getInt(process);
    } catch (Exception e) {
        return -1;
    }
}
Run Code Online (Sandbox Code Playgroud)

只要确保返回值不为-1即可。如果是,则解析 的输出ps

  • 它不适用于“java.lang.ProcessImpl”。例如,在 Windows 上它对我来说失败了。 (6认同)