Java 9 – Process API Updates (JEP-102) | Code Factory


Index Page : Link

Donate : Link

Medium Blog : Link

Applications : Link

Unitl java 8, communicating with processor/os/machine is very difficult. We required to write very complex native code and we have to use 3rd party jar files.

The way of communication with processor is varied from system to system (i.e. os to os). For example, in windows one way, but in Mac other way. Being a programmer we have to write code based on operating system, which makes programming very complex.

To resolve this complexity, JDK 9 engineers introduced several enhancements to Process API. By using this Updated API, we can write java code to communicate with any processor very easily. According to worldwide Java Developers, Process API Updates is the number 1 feature in Java 9.

With this Enhanced API, we can perform the following activities very easily.

  1. Get the Process ID (PID) of running process.
  2. Create a new process
  3. Destroy already running process
  4. Get the process handles for processes
  5. Get the parent and child processes of running process
  6. Get the process information like owner, children,…
    etc…

What’s New in Java 9 Process API:

  1. Added several new methods (like pid(),info() etc) to Process class.
  2. Added several new methods (like startPipeline()) to ProcessBuilder class. We can use ProcessBuilder class to create operating system processes.
  3. Introduced a new powerful interface ProcessHandle. With this interface, we can access current running process, we can access parent and child processes of a particular process etc.
  4. Introduced a new interface ProcessHandle.Info, by using this we can get complete information of a particular process.

Note: All these classes and interfaces are part of java.lang package and hence we are not required to use any import statement.

How to get ProcessHandle object:

It is the most powerful and useful interface introduced in java 9.

We can get ProcessHandle object as follows

1. ProcessHandle handle = ProcessHandle.current();
Returns the ProcessHandle of current running Process

2. ProcessHandle handle = p.toHandle();
Returns the ProcessHandle of specified Process object.

3. Optional handle = ProcessHandle.of(PID);
Returns the ProcessHandle of proccess with the specified pid.
Here, the return type is Optional, because PID may exist or may not exist.

Use Case-1: To get the process ID (PID) of current process

public class Test
{
	public static void main(String... args) throws Exception
	{
		ProcessHandle ph = ProcessHandle.current();
		long pid = ph.pid();
		System.out.println("PID of current running JVM inbstance is : " + pid);
		Thread.sleep(100000);
	}
}
D:\CodeFactory>javac Test.java

D:\CodeFactory>java Test
PID of current running JVM inbstance is : 11568

We can see this process id in Task Manager (alt+ctrl+delete in windows)

ProcessHandle.Info:

We can get complete information of a particular process by using ProcessHandle.Info object.
We can get this Info object as follows.

ProcessHandle ph = ProcessHandle.current();
ProcessHandle.Info info = ph.info();

Once we got Info object, we can call the following methods on that object.

1. user()
Return the user of the process.
public Optional user()

2. command():
Returns the command, that can be used to start the process.
public Optional command()

3. startInstant():
Returns the start time of the process.
public Optional startInstant()

4. totalCpuDuration():
Returns the total cputime accumulated of the process.
public Optional totalCpuDuration()

Use Case-2: To get snapshot of the current running process info

public class Test
{
	public static void main(String... args) throws Exception
	{
		ProcessHandle ph = ProcessHandle.current();
		ProcessHandle.Info info = ph.info();
		System.out.println("Complete Process Information : " + info);
		System.out.println("User : " + info.user().get());
		System.out.println("Command : " + info.command().get());
		System.out.println("Start Time : " + info.startInstant().get());
		System.out.println("Total CPU Time Acquired : " + info.totalCpuDuration().get());
	}
}
D:\CodeFactory>javac Test.java

D:\CodeFactory>java Test
Complete Process Information : [user: Optional[CODEFACTORY\34CodeFactory], cmd: C:\Program Files\Java\jdk-11.0.10\bin\java.exe, startTime: Optional[2023-06-22T13:45:17.190Z], totalTime: Optional[PT0.328125S]]
User : CODEFACTORY\34CodeFactory
Command : C:\Program Files\Java\jdk-11.0.10\bin\java.exe
Start Time : 2023-06-22T13:45:17.190Z
Total CPU Time Acquired : PT0.328125S

Use Case-3: To get snapshot of the Particular Process Based on id

import java.util.*;

public class Test
{
	public static void main(String... args) throws Exception
	{
		getProcess(900);
		getProcess(123);
	}

	private static void getProcess(int id) {
		Optional<ProcessHandle> oph = ProcessHandle.of(id);
		ProcessHandle ph = oph.get();
		ProcessHandle.Info info = ph.info();
		System.out.println("Complete Process Information : " + info);
		System.out.println("User : " + info.user().get());
		System.out.println("Command : " + info.command().get());
		System.out.println("Start Time : " + info.startInstant().get());
		System.out.println("Total CPU Time Acquired : " + info.totalCpuDuration().get());
	}
}
D:\CodeFactory>javac Test.java

D:\CodeFactory>java Test
Complete Process Information : [user: Optional[CODEFACTORY\34CodeFactory], cmd: C:\Windows\System32\cmd.exe, startTime: Optional[2023-06-22T13:44:57.667Z], totalTime: Optional[PT0.109375S]]
User : CODEFACTORY\34CodeFactory
Command : C:\Windows\System32\cmd.exe
Start Time : 2023-06-22T13:44:57.667Z
Total CPU Time Acquired : PT0.109375S

Exception in thread "main" java.util.NoSuchElementException: No value present
        at java.base/java.util.Optional.get(Optional.java:148)
        at Test.getProcess(Test.java:13)
        at Test.main(Test.java:8)

ProcessBuilder:

We can use ProcessBuilder to create processes.
We can create ProcessBuilder object by using the following constructor.

public ProcessBuilder(String… command)

The argument should be valid command to invoke the process.

ProcessBuilder pb = new ProcessBuilder("javac","Test.java");
ProcessBuilder pb = new ProcessBuilder("java","Test");
ProcessBuilder pb = new ProcessBuilder("notepad.exe","D:\\names.txt");

Once we create a ProcessBuilder object, we can start the process by using start() method. Ex. pb.start()

Use Case-4: To create and Start a process by using ProcessBuilder

FrameDemo.java:

import java.awt.*;
import java.awt.event.*;

public class FrameDemo
{
	public static void main(String... args)
	{
		Frame f = new Frame();
		f.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				System.exit(0);
			}
		});
		f.add(new Label("This process started from Java by using ProcessBuilder"));
		f.setSize(400, 200);
		f.setVisible(true);
	}
}

Test.java

public class Test
{
	public static void main(String... args) throws Exception
	{
		processBuilder("javac", "FrameDemo.java");
		processBuilder("java", "FrameDemo");
	}

	private static void processBuilder(String arg1, String arg2) throws Exception
	{
		ProcessBuilder pb = new ProcessBuilder(arg1, arg2);
		Process process = pb.start();
		// class file of FrameDemo got created during execution (java Test)
		// need to call waitFor() otherwise it will complete execution of the process and we unable to see the window 
		process.waitFor();
	}
}
D:\CodeFactory>javac Test.java

D:\CodeFactory>java Test

Use Case-5: To open a file with notepad from java by using ProcessBuilder

public class Test
{
	public static void main(String... args) throws Exception
	{
		new ProcessBuilder("notepad.exe", "FrameDemo.java").start();
	}
}

Use Case-6: To start and destroy a process from java by using ProcessBuilder

public class Test
{
	public static void main(String... args) throws Exception
	{
		ProcessBuilder pb = new ProcessBuilder("java", "FrameDemo");
		Process p = pb.start();
		System.out.println("Process started with id : " + p.pid());
		Thread.sleep(5000);
		System.out.println("Destroying the process with id : " + p.pid());
		p.destroy();
	}
}
D:\CodeFactory>javac Test.java

D:\CodeFactory>java Test
Process started with id : 7212
// window get opened and closed after 5 seconds
Destroying the process with id : 7212

Use Case-7: To destroy a process which is not created from Java

import java.util.*;

public class Test
{
	public static void main(String... args) throws Exception
	{
		// get processId from Task Manager > Details
		Optional<ProcessHandle> oph = ProcessHandle.of(14044);
		ProcessHandle ph = oph.get();
		ph.destroy();
	}
}

Use Case-8: To display all running process information

import java.util.*;
import java.util.stream.*;
import java.time.*;

public class Test
{
	public static void main(String... args) throws Exception
	{
		Stream<ProcessHandle> allProcesses = ProcessHandle.allProcesses();
		allProcesses.limit(5).forEach(ph -> dumpProcessInfo(ph));
	}

	private static void dumpProcessInfo(ProcessHandle ph)
	{
		ProcessHandle.Info info = ph.info();
		System.out.println("Process Id : " + ph.pid());
		System.out.println("User : " + info.user().orElse(""));
		System.out.println("Command : " + info.command().orElse(""));
		System.out.println("Start Time : " + info.startInstant().orElse(Instant.now()));
		System.out.println("Total CPU Time Acquired : " + info.totalCpuDuration().orElse(Duration.ofMillis(0)).toMillis());
		System.out.println();
	}
}

Output:

D:\CodeFactory>javac Test.java

D:\CodeFactory>java Test
Process Id : 0
User :
Command :
Start Time : 2023-06-22T14:47:20.967773600Z
Total CPU Time Acquired : 0

Process Id : 4
User :
Command :
Start Time : 2023-06-22T14:47:21.004054100Z
Total CPU Time Acquired : 0

Process Id : 56
User :
Command :
Start Time : 2023-06-22T14:47:21.014143500Z
Total CPU Time Acquired : 0

Process Id : 104
User :
Command :
Start Time : 2023-06-22T14:47:21.018246900Z
Total CPU Time Acquired : 0

Process Id : 404
User :
Command :
Start Time : 2023-06-22T14:47:21.029423900Z
Total CPU Time Acquired : 0

Use Case-9: To display all child process information

import java.util.*;
import java.util.stream.*;
import java.time.*;

public class Test
{
	public static void main(String... args) throws Exception
	{
		Optional<ProcessHandle> oph = ProcessHandle.of(900);
		ProcessHandle ph = oph.get();
		Stream<ProcessHandle> children = ph.children();
		children.limit(5).forEach(p -> dumpProcessInfo(p));
	}

	private static void dumpProcessInfo(ProcessHandle ph)
	{
		ProcessHandle.Info info = ph.info();
		System.out.println("Process Id : " + ph.pid());
		System.out.println("User : " + info.user().orElse(""));
		System.out.println("Command : " + info.command().orElse(""));
		System.out.println("Start Time : " + info.startInstant().orElse(Instant.now()));
		System.out.println("Total CPU Time Acquired : " + info.totalCpuDuration().orElse(Duration.ofMillis(0)).toMillis());
		System.out.println();
	}
}

Output:

D:\CodeFactory>java Test
Process Id : 8848
User : CODEFACTORY\34CODEFACTORY
Command : C:\Windows\System32\conhost.exe
Start Time : 2023-06-22T13:44:57.711Z
Total CPU Time Acquired : 3390

Process Id : 10024
User : CODEFACTORY\34CODEFACTORY
Command : C:\Program Files\Common Files\Oracle\Java\javapath_target_655068375\java.exe
Start Time : 2023-06-22T14:53:58.204Z
Total CPU Time Acquired : 93

Note: If Process not having any child processes then we won’t get any output

Use Case-10: To perform a task at the time of Process Termination

import java.util.concurrent.*;

public class Test
{
	public static void main(String... args) throws Exception
	{
		ProcessBuilder pb = new ProcessBuilder("java", "FrameDemo");
		Process p = pb.start();
		System.out.println("Process started with id : " + p.pid());
		CompletableFuture<Process> future = p.onExit();
		future.thenAccept(p1 -> System.out.println("Process termination with id : " + p1.pid()));
		System.out.println(future.get());
	}
}

Output:

D:\CodeFactory>javac Test.java

// output during normal close/termination
D:\CodeFactory>java Test
Process started with id : 1212
Process[pid=1212, exitValue=0]
Process termination with id : 1212

// output during close/terminavtion of window from TaskManager (abnormal termination)
D:\CodeFactory>java Test
Process started with id : 3444
Process[pid=3444, exitValue=1]
Process termination with id : 3444

Note: Observe exit value: 0 for normal termination and non-zero for abnormal termination

Leave a comment