GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • java.evolved
  • ←
  • →

This view

  • Original page
  • New address

GeezerVison is showing javaevolved.dev — Modern Process API | java.evolved

Home / Concurrency / Modern Process API
Concurrency Intermediate

Modern Process API

  • 🐛 Report a code issue
  • 🌐 Report a translation issue
  • 💡 Suggest a new pattern

Inspect and manage OS processes with ProcessHandle.

Concurrency
Code Comparison
✕ Java 8
Process p = Runtime.getRuntime()
    .exec("ls -la");
int code = p.waitFor();
// no way to get PID
// no easy process info
✓ Java 9+
ProcessHandle ph =
    ProcessHandle.current();
long pid = ph.pid();
ph.info().command()
    .ifPresent(IO::println);
ph.children().forEach(
    c -> IO.println(c.pid()));
Share 𝕏
See a problem with this code? Let us know.
Why the modern way wins
🔍

Full info

Access PID, command, arguments, start time, CPU usage.

🌳

Process tree

Navigate parent, children, and descendants.

📊

Monitoring

onExit() returns a CompletableFuture for async monitoring.

Old Approach
Runtime.exec()
Modern Approach
ProcessHandle
Since JDK
9
Difficulty
Intermediate
JDK Support
Modern Process API
Available

Widely available since JDK 9 (Sept 2017)

How it works

ProcessHandle provides PIDs, process info (command, arguments, start time, CPU usage), parent/child relationships, and process destruction. No more undocumented Process internals.

Related Documentation
ProcessHandle ↗ Process API (JEP 102) ↗
Proof
View proof source ↗
Related patterns
Concurrency Advanced

Scoped values

Java 8
static final ThreadLocal<User> CURRENT =
    new ThreadLocal<>();
void handle(Request req) {
    CURRENT.set(authenticate(req));
    try { process(); }
    finally { CURRENT.remove(); }
}
Java 25
static final ScopedValue<User> CURRENT =
    ScopedValue.newInstance();
void handle(Request req) {
    ScopedValue.where(CURRENT,
        authenticate(req)
    ).run(this::process);
}
Hover to see modern ➜
JDK 25+ →
Concurrency Intermediate

Concurrent HTTP with virtual threads

Java 8
ExecutorService pool =
    Executors.newFixedThreadPool(10);
List<Future<String>> futures =
    urls.stream()
    .map(u -> pool.submit(
        () -> fetchUrl(u)))
    .toList();
// manual shutdown, blocking get()
Java 21+
try (var exec = Executors
    .newVirtualThreadPerTaskExecutor()) {
    var results = urls.stream()
        .map(u -> exec.submit(
            () -> client.send(req(u),
                ofString()).body()))
        .toList().stream()
        .map(Future::join).toList();
}
Hover to see modern ➜
JDK 21+ →
Concurrency Intermediate

CompletableFuture chaining

Pre-Java 8
Future<String> future =
    executor.submit(this::fetchData);
String data = future.get(); // blocks
String result = transform(data);
Java 8+
CompletableFuture.supplyAsync(
    this::fetchData
)
.thenApply(this::transform)
.thenAccept(IO::println);
Hover to see modern ➜
JDK 8+ →
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.