Concurrent HTTP with virtual threads
Code Comparison
ExecutorService pool =
Executors.newFixedThreadPool(10);
List<Future<String>> futures =
urls.stream()
.map(u -> pool.submit(
() -> fetchUrl(u)))
.toList();
// manual shutdown, blocking get()
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();
}
Why the modern way wins
♾️
Thread per request
No pool sizing — one virtual thread per URL.
📖
Simple code
Write straightforward blocking code.
⚡
High throughput
Thousands of concurrent requests with minimal resources.
Old Approach
Thread Pool + URLConnection
Modern Approach
Virtual Threads + HttpClient
JDK Support
Concurrent HTTP with virtual threads
Available
Widely available since JDK 21 LTS (Sept 2023)
How it works
Virtual threads make it practical to create a thread per HTTP request. Combined with HttpClient, this replaces complex async callback patterns with simple blocking code that scales.
Related Documentation
Proof