This is a quick introduction to application of Java ProcessHandle through a use case.
Background:
I developed a website call ps2pdf.com. It uses a range of free software to process user requests. To put it simply, it is an orchestrator for bunch of free opensource software such as FFMPEG. While there are libraries that allows me to use most of these software directly from my Java application (Mostly though JNI), they are always bit outdated or unstable. I, being a brave programmer, choose to use Java ProcessBuilder and Process to execute programs such as FFMPEG with arguments. Managing of processes spawn like that is bit chaotic. Until the release of Java 9, I had a code that mainly uses Runtime.getRuntime().exec("ps aux...")
to find and kill processes that hangs or exceed time limit. I had quite a bit of code, an ugly code, written to manage processes. I got really exited when I came across Java 9 ProcessHandle interface. It exposes many information about processes running on a machine (specifically when used in Linux systems) which I could use to do a major cleanup.
About ProcessHandle:
Java ProcessHandle提供了本机进程的接口。 接口允许阅读信息关于流程的信息,例如检查某个流程是否处于活动状态或调用简单的操作在诸如杀死它的过程中。
Use case:
我将通过以下用例向您介绍,该用例曾用于解释ProcessHandle接口的一些有用部分。
- 获取系统上所有正在运行的进程Filter ffmpeg processes that meets a certain criteria检查它们是否正在运行检查它们是否正在运行 for more than 4 hours检查输入到ffmpeg的输入文件是否已删除杀死所有挂起的ffmpeg进程
Step 1: Finding all processes
Stream<ProcessHandle> allProcesses = ProcessHandle.allProcesses();
Step 2: Filter processes
Stream<ProcessHandle> toDeleteProcessHandles = allProcesses.filter(processHandle -> {
// Check if process is alive
if(processHandle.isAlive()){
Info info = processHandle.info();
String executableWithPath = info.command().orElse(null);
// Check if this is an ffmpeg instant
if(executableWithPath != null && executableWithPath.endsWith("ffmpeg")){
// Check if they are running for more than 4 hours
if(Duration.between(Instant.now(), info.startInstant().get()).toHours() > 4){
// Check if input file fed on to ffmpeg is deleted
String[] arguments = info.arguments().orElse(null);
String inputFile = Arrays.stream(arguments).filter(arg -> arg.startsWith("/home/username/content/input")).findFirst().orElse(null);
if(inputFile != null && !Files.exists(Paths.get(inputFile))){
return true;
}
}
}
}
return false;
});
Step 3: Kill hanged processes
toDeleteProcessHandles.forEach(processHandle -> processHandle.destroy());
This interface combined with Stream API allow writing concise code. You may have noticed that I used orElse(null)
in some places. Which is from Java Optional class introduced in Java 1.8 with Stream API. You can further clean up this code by using methods such is isPresent()
on Optional class instead of clustering with someVariable != null && doSomethingWithSomeVariable
inside if expressions checks.
这个类的另一个有用的静态方法是
ProcessHandle handle = ProcessHandle.of(long pid);
当您使用ProcessBuilder启动流程或具有Java Process对象时,这很有用。 尽管Java Process对象(Java 9+)公开了进程的PIDsomeProcess.pid()。 您可以使用的ProcessHandle.of()跟踪过程。
You could find more about ProcessHandle and ProcessHandle.Info by reading their documentation.
This very code is in action every time someone convert a video or compresses a jpeg on PDF2PDF.
感谢您的阅读。 欢迎您提出问题或提出反馈。