[java] How to get PID of process I've just started within java program?

I've started a process with following code

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

Now I need to know the process's pid that I've just started.

This question is related to java process pid processbuilder

The answer is


This page has the HOWTO:

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

On Windows:

Runtime.exec(..)

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.


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

package com.panayotis.wrapper;

import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;

public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
        ProcessBuilder pb = new ProcessBuilder(args);
        pb.directory(new File(System.getProperty("user.dir")));
        pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectError(ProcessBuilder.Redirect.INHERIT);
        pb.start().waitFor();
    }
}

To use it, create a jar file with just this one, and call it with command arguments this:

String java = System.getProperty("java.home") + separator + "bin" + separator + "java.exe";
String jar_wrapper = "path\\of\\wrapper.jar";

String[] args = new String[]{java, "-cp", jar_wrapper, "com.panayotis.wrapper.Main", actual_exec_args...);

Since Java 9 class Process has new method long pid(), so it is as simple as

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

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


One solution is to use the idiosyncratic tools the platform offers:

private static String invokeLinuxPsProcess(String filterByCommand) {
    List<String> args = Arrays.asList("ps -e -o stat,pid,unit,args=".split(" +"));
    // Example output:
    // Sl   22245 bpds-api.service                /opt/libreoffice5.4/program/soffice.bin --headless
    // Z    22250 -                               [soffice.bin] <defunct>

    try {
        Process psAux = new ProcessBuilder(args).redirectErrorStream(true).start();
        try {
            Thread.sleep(100); // TODO: Find some passive way.
        } catch (InterruptedException e) { }

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(psAux.getInputStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (!line.contains(filterByCommand))
                    continue;
                String[] parts = line.split("\\w+");
                if (parts.length < 4)
                    throw new RuntimeException("Unexpected format of the `ps` line, expected at least 4 columns:\n\t" + line);
                String pid = parts[1];
                return pid;
            }
        }
    }
    catch (IOException ex) {
        log.warn(String.format("Failed executing %s: %s", args, ex.getMessage()), ex);
    }
    return null;
}

Disclaimer: Not tested, but you get the idea:

  • Call ps to list the processes,
  • Find your one because you know the command you launched it with.
  • If there are multiple processes with the same command, you can:
    • Add another dummy argument to differentiate them
    • Rely on the increasing PID (not really safe, not concurrent)
    • Check the time of process creation (could be too coarse to really differentiate, also not concurrent)
    • Add a specific environment variable and list it with ps too.

Using JNA, supporting old and new JVM to get process id

public static long getProcessId(Process p){
    long pid = -1;
    try {
      pid = p.pid();
    } catch (NoSuchMethodError e) {
        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));
                pid = 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);
                pid = f.getLong(p);
                f.setAccessible(false);
            }
        }
        catch(Exception ex)
        {
            pid = -1;
        }
    }        
    return pid;
}

I think I have found out a solution, that looks quite bulletproof while working on most platforms. Here is the idea:

  1. Create a JVM-wide mutex that you acquire before spawning new process/killing a process
  2. Use platform-dependent code to acquire list of child processes + pids of your JVM process
  3. Spawn new process
  4. Acquire new list of child processes + pids and compare with the previous list. The one that is new is your guy.

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

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;
        }
    }
}

For GNU/Linux & MacOS (or generally UNIX like) systems, I've used below method which works fine:

private int tryGetPid(Process process)
{
    if (process.getClass().getName().equals("java.lang.UNIXProcess"))
    {
        try
        {
            Field f = process.getClass().getDeclaredField("pid");
            f.setAccessible(true);
            return f.getInt(process);
        }
        catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e)
        {
        }
    }

    return 0;
}

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 that Process is an abstract class). If your UNIX implementation is like mine, you will see an implementation class that has a property named pid that contains the PID of the process. Here is the logging code that I used.

    //--------------------------------------------------------------------
    // Jim Tough - 2014-11-04
    // This temporary Reflection code is used to log the name of the
    // class that implements the abstract Process class on the target
    // JRE, all of its 'Fields' (properties and methods) and the value
    // of each field.
    //
    // I only care about how this behaves on our UNIX servers, so I'll
    // deploy a snapshot release of this code to a QA server, run it once,
    // then check the logs.
    //
    // TODO Remove this logging code before building final release!
    final Class<?> clazz = process.getClass();
    logger.info("Concrete implementation of " + Process.class.getName() +
            " is: " + clazz.getName());
    // Array of all fields in this class, regardless of access level
    final Field[] allFields = clazz.getDeclaredFields();
    for (Field field : allFields) {
        field.setAccessible(true); // allows access to non-public fields
        Class<?> fieldClass = field.getType();
        StringBuilder sb = new StringBuilder(field.getName());
        sb.append(" | type: ");
        sb.append(fieldClass.getName());
        sb.append(" | value: [");
        Object fieldValue = null;
        try {
            fieldValue = field.get(process);
            sb.append(fieldValue);
            sb.append("]");
        } catch (Exception e) {
            logger.error("Unable to get value for [" +
                    field.getName() + "]", e);
        }
        logger.info(sb.toString());
    }
    //--------------------------------------------------------------------

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 the EXPECTED_IMPL_CLASS_NAME and EXPECTED_PID_FIELD_NAME constants to make it work for you.

/**
 * Get the process id (PID) associated with a {@code Process}
 * @param process {@code Process}, or null
 * @return Integer containing the PID of the process; null if the
 *  PID could not be retrieved or if a null parameter was supplied
 */
Integer retrievePID(final Process process) {
    if (process == null) {
        return null;
    }

    //--------------------------------------------------------------------
    // Jim Tough - 2014-11-04
    // NON PORTABLE CODE WARNING!
    // The code in this block works on the company UNIX servers, but may
    // not work on *any* UNIX server. Definitely will not work on any
    // Windows Server instances.
    final String EXPECTED_IMPL_CLASS_NAME = "java.lang.UNIXProcess";
    final String EXPECTED_PID_FIELD_NAME = "pid";
    final Class<? extends Process> processImplClass = process.getClass();
    if (processImplClass.getName().equals(EXPECTED_IMPL_CLASS_NAME)) {
        try {
            Field f = processImplClass.getDeclaredField(
                    EXPECTED_PID_FIELD_NAME);
            f.setAccessible(true); // allows access to non-public fields
            int pid = f.getInt(process);
            return pid;
        } catch (Exception e) {
            logger.warn("Unable to get PID", e);
        }
    } else {
        logger.warn(Process.class.getName() + " implementation was not " +
                EXPECTED_IMPL_CLASS_NAME + " - cannot retrieve PID" +
                " | actual type was: " + processImplClass.getName());
    }
    //--------------------------------------------------------------------

    return null; // If PID was not retrievable, just return null
}

In my testing all IMPL classes had the field "pid". This has worked for me:

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;
    }
}

Just make sure the returned value is not -1. If it is, then parse the output of ps.


There is no public API for this yet. see Sun Bug 4244896, Sun Bug 4250622

As a workaround:

Runtime.exec(...)

returns an Object of type

java.lang.Process

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 called pid. Using Reflection you can easily get the value of this field. This is admittedly a hack, but it might help. What do you need the PID for anyway?


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 the tasklist 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.


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).


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.

Process process = //...;
WinProcess wp = new WinProcess(process);
int pid = wp.getPid();

In Unix System (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;
  }

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.


Include jna (both "JNA" and "JNA Platform") in your library and use this function:

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;
    }

You can also download JNA from here and JNA Platform from here.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to process

Fork() function in C How to kill a nodejs process in Linux? Xcode process launch failed: Security Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes Linux Script to check if process is running and act on the result CreateProcess error=2, The system cannot find the file specified How to make parent wait for all child processes to finish? How to use [DllImport("")] in C#? Visual Studio "Could not copy" .... during build How to terminate process from Python using pid?

Examples related to pid

How to get PID by process name? Why is $$ returning the same id as the parent process? How to get PID of process by specifying process name and store it in a variable to use further? ERROR! MySQL manager or server PID file could not be found! QNAP How to get the PID of a process by giving the process name in Mac OS X ? Determine the process pid listening on a certain port What is a .pid file and what does it contain? How to get PID of process I've just started within java program? How to check if a process id (PID) exists How does a Linux/Unix Bash script know its own PID?

Examples related to processbuilder

ProcessBuilder: Forwarding stdout and stderr of started processes without blocking the main thread Difference between ProcessBuilder and Runtime.exec() Java Programming: call an exe from Java and passing parameters How to get PID of process I've just started within java program? Executing another application from Java