ZT Process Killer
August 6, 2026 · View on GitHub
Continuous Integration
Quick Overview
The project was created in ZeroTurnaround to have a stable base functionality of stopping running processes from Java. It can stop processes started from Java (e.g. with zt-exec) as well as existing system processes based on their process ID (PID).
Installation
The project artifacts are available in Maven Central Repository.
Maven:
<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>zt-process-killer</artifactId>
<version>1.12.0</version>
</dependency>
Gradle:
implementation("org.zeroturnaround:zt-process-killer:1.12.0")
The library requires Java 8 or later at runtime.
Building
The project is built with Gradle via the bundled wrapper, so no local Gradle installation is required:
./gradlew build
The library targets Java 8 bytecode. The build resolves a Java 8 toolchain automatically (it is downloaded on demand if not already installed), so the build itself runs on any modern JDK.
Releasing
Versions follow Semantic Versioning (MAJOR.MINOR.PATCH, e.g. 1.12.0)
and release tags use the vMAJOR.MINOR.PATCH form (e.g. v1.12.0). Tags created before this
convention use the older zt-process-killer-<version> form.
Releases are cut with the Release GitHub Actions workflow (Actions → Release → Run workflow).
It takes the release version (e.g. 1.12.0) and then builds, publishes to Maven Central, tags
the commit, creates the GitHub release, and sets the next development version.
The workflow also promotes the ## [Unreleased] section of CHANGELOG.md into a
dated ## [x.y.z] section and updates the comparison links, so the only changelog task is to make
sure the changes being released are listed under ## [Unreleased] beforehand. (The release fails
if that section is empty.)
Motivation
In Java Process.destroy() is ambiguous. On Windows it terminates processes forcibly. On UNIX it terminates them gracefully. As invoking kill commands from Java is errorprone it should have an advised API and good test coverage.
We had the following functional requirements:
- check whether a process is alive
- wait until a process has finished
- terminate a process gracefully (by default disabled on Windows as it's unsupported - WindowsProcess)
- terminate a process forcibly
- get the process ID (PID) of running JVM
and these non-functional requirements:
- abstraction of processes regardless they are started from Java or not (use process ID) - SystemProcess
- have process API similar to java.lang.Process
- all waiting methods should have one version with timeout and another without it
- stopping operation should be idempotent - if a process was already finished it is a success
- separate generic behavior from process implementation - ProcessUtil
- support alternative implementations for stopping same process - OrProcess
- simple factory for creating process instances - Processes
- invoke Java 8 java.lang.Process methods if possible - Java8Process
Limitations:
- As the process abstraction is also used for already running processes it can't access their streams or exit value.
- The scope of this project is stopping single processes. However WindowsProcess has method setIncludeChildren to also stop child processes in case the root process is still running.
Examples
- Get my PID
int pid = PidUtil.getMyPid();
System.out.println("My PID is " + pid);
- Check whether a PID is alive
int pid = Integer.parseInt(FileUtils.readFileToString(new File("pidfile")));
PidProcess process = Processes.newPidProcess(pid);
boolean isAlive = process.isAlive();
System.out.println("PID " + pid + " is alive: " + isAlive);
- Check whether a process is alive
Process p = new ProcessBuilder("my-application").start();
JavaProcess process = Processes.newJavaProcess(p);
boolean isAlive = process.isAlive();
System.out.println("Process " + process + " is alive: " + isAlive);
- Wait until an already started process has finished
int pid = Integer.parseInt(FileUtils.readFileToString(new File("pidfile")));
PidProcess process = Processes.newPidProcess(pid);
boolean finished = process.waitFor(10, TimeUnit.MINUTES);
System.out.println("PID " + pid + " finished on time: " + finished);
- Wait until the started process has finished
Process p = new ProcessBuilder("my-application").start();
JavaProcess process = Processes.newJavaProcess(p);
boolean finished = process.waitFor(10, TimeUnit.MINUTES);
System.out.println("Process " + process + " finished on time: " + finished);
- Stop an already started process, timeout of 30 seconds for graceful stop, timeout of 10 seconds for forceful stop
int pid = Integer.parseInt(FileUtils.readFileToString(new File("pidfile")));
PidProcess process = Processes.newPidProcess(pid);
ProcessUtil.destroyGracefullyOrForcefullyAndWait(process, 30, TimeUnit.SECONDS, 10, TimeUnit.SECONDS);
- Stop the started process, timeout of 30 seconds for graceful stop, timeout of 10 seconds for forceful stop
Process p = new ProcessBuilder("my-application").start();
SystemProcess process = Processes.newStandardProcess(p);
ProcessUtil.destroyGracefullyOrForcefullyAndWait(process, 30, TimeUnit.SECONDS, 10, TimeUnit.SECONDS);