One virtual thread per session
Every active session runs on its own virtual thread. Virtual threads are cheap (thousands per JVM) and yield automatically on blocking I/O. This is why you can have 10,000 concurrent sessions on a single instance.
Advertisement
Blocking is fine in tools
You don't need CompletableFuture or reactive libraries. Just call the API synchronously:
public Object call(Map args) {
return httpClient.send( // blocking
request,
HttpResponse.BodyHandlers.ofString()
);
} Advertisement
What to avoid
Synchronized blocks and Object.wait() pin virtual threads to their carrier, defeating the whole model. Use ReentrantLock or higher-level concurrency utilities instead.