How to get the PID of a process that I just started in a java program?

I started the process with the following code

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

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

+66
java process pid processbuilder
Jan 20 '11 at 17:30
source share
16 answers

There is no public API yet. see Sun Error 4244896 , Sun Error 4250622

As a workaround:

 Runtime.exec(...) 

returns an object of type

 java.lang.Process 

The Process class is abstract, and you return to some subclass of the process that is designed for your operating system. For example, on a Mac, 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 can help. What do you need pid ?

+25
Jan 20 2018-11-17T00:
source share
— -

This page has a 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 descriptor.

This is the OS handle for the process. You will have to use this + Win32 API to request a PID. This page has information on how to do this.

+24
Apr 07 2018-11-11T00:
source share

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

 ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "path"); try { Process p = pb.start(); long pid = p.getPid(); } catch (IOException ex) { // ... } 
+24
Feb 08 '17 at 3:13
source share

On a Unix system (Linux and 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; } 
+19
16 Oct. '15 at 13:33
source share

Include jna in your library and use this function:

 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; } 
+14
Apr 15 '17 at 13:52 on
source share

I think I found a solution that looks pretty bulletproof when working on most platforms. Here is an idea:

  • Create a mutex in the JVM format that you will acquire before creating a new process / killing a process.
  • Use platform-specific code to get the list of child processes + pids of your JVM process
  • Create a new process
  • Get a new list of child processes + pids and compare with the previous list. Your boyfriend is new.

Since you only check child processes, you cannot be allowed by any other process on the same machine. Mutex in JVM format, which allows you to be sure that the new process is correct.

Reading a list of child processes is easier than getting the PID from process objects, since it does not require WIN API calls on Windows and, more importantly, it has already been done in several libraries.

The following is an implementation of the above idea using the 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 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; } } } 
+8
Mar 22 '12 at 15:07
source share

In my testing, all IMPL classes had a "pid" field. This 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 return value is not -1. If so, then analyze the output of ps .

+3
Apr 01 '15 at 23:30
source share

I used a non-portable approach to extract a UNIX identifier from a Process object, which is very simple.

STEP 1: Use some Reflection API calls to identify the Process implementation class on the target JRE server (remember that Process is an abstract class). If your UNIX implementation is similar to mine, you will see an implementation class that has a property called pid that contains the process PID. Here is the registration code 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 the field name that you received in the Reflection log, write some code for the pickpocket class of the Process implementation and extract the PID from it using the Reflection API. The code below works for me to my taste of UNIX. You may need to configure the EXPECTED_IMPL_CLASS_NAME and EXPECTED_PID_FIELD_NAME constants to 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 } 
+2
Nov 04 '14 at 16:10
source share

This is not a general answer.

However: Some programs, especially services and long-running programs, create (or suggest creating, optionally) a "pid file".

For example, LibreOffice offers --pidfile={file} , see docs .

I was looking for enough time to solve Java / Linux, but the PID was (in my case) on hand.

+1
Dec 12 '17 at 19:15
source share

There is no easy solution. The way I did this in the past is to start another process to run the ps command on Unix-like systems or the tasklist on Windows, and then analyze the output of this command for the PID I want. In fact, I put this code in a separate script wrapper for each platform that just returned the PID so that I can leave the Java piece as independent of the platform as possible. This does not work for short-term tasks, but it is not a problem for me.

0
Jan 20 '11 at 19:07
source share

jnr-process provides this feature.

This is part of the java embedded environment used by jruby and may be considered the prototype of the future java-FFI

0
Aug 19 '15 at 13:27
source share

I believe that the only portable way to do this is to start the (child) process through another (parent) Java process, which will tell me the actual PID of the parent process. Children's process can be anything.

The code for this wrapper

 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 that name only and call it using the command arguments:

 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...); 
0
Aug 08 '17 at 9:49 on
source share

If portability is not a concern, and you just want to get a pid on Windows without the hassle of using code that has been tested and is known to work on all modern versions of Windows, you can use kohsuke winp . It is also available on Maven Central for easy use.

 Process process = //...; WinProcess wp = new WinProcess(process); int pid = wp.getPid(); 
0
Sep 07 '17 at 12:26
source share

There is an open source library that has such a function and has a cross-platform implementation: https://github.com/OpenHFT/Java-Thread-Affinity

It might be too hard to get a PID, but if you need other things, such as a processor and thread identifier, and in particular, thread binding, it might be appropriate for you.

To get the current thread id, simply call Affinity.getAffinityImpl().getProcessId() .

This is implemented using JNA (see arcsin answer).

0
Nov 02 '17 at 14:59
source share

One solution is to use the unique tools that 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 verified, but you get the idea:

  • Call ps to list the processes
  • Find yours because you know the team with which you started it.
  • If there are several processes with the same command, you can:
    • Add another dummy argument to distinguish them
    • Rely on an increasing PID (not entirely secure, not parallel)
    • Check process creation time (may be too coarse to really differentiate, but also not parallel)
    • Add a special environment variable and list it with ps .
0
Dec 12 '17 at 19:19
source share

You can extract the pid from the bean runtime, as in:

 ManagementFactory.getRuntimeMXBean().getName() 

It consists of pid @hostname, so you can easily get pid with a simple regular expression.

For runtime information (free memory, loading, available cpus, etc.) you can use:

 Runtime.getRuntime() 
-2
Aug 6 '16 at 22:51
source share



All Articles