Concurrent HTTP with virtual threads
Fetch many URLs concurrently with virtual threads and HttpClient.
Code Comparison
✕ 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();
}
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
Since JDK
21
Difficulty
intermediate
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.