When we use .parallelStream()
in Java, we expect parallelism to magically kick in — blazing fast execution across multiple threads.
But sometimes, even with .parallelStream()
, everything still runs in a single thread. No speedup. No parallelism. Just disappointment. 😤
🧪 The Initial Code
I had this pattern:
List<String> users = List.of("alice", "bob");
List<String> products = IntStream.range(0, 10_000)
.mapToObj(i -> "product-" + i)
.toList();
List<String> result = users.stream()
.flatMap(user ->
products.parallelStream()
.map(product -> {
System.out.println("Sequential map: " + user + " - " + product + " on " + Thread.currentThread().getName());
return user + " → " + product;
})
)
.toList();
Looks fine, right?
🤯 But It Wasn’t Parallel
When I ran it, the output showed every single operation happening in the same thread.
Even though I used .parallelStream()
!
Turns out this pattern is broken. Why?
🧠 Why It Doesn’t Work
A much better and simpler explanation than my original article was shared by aleatorio.dev.br on Bluesky 🙌
“The answer lies in the implementation of flatMap, which takes a parallel stream and forcibly calls .sequential() on it, turning it back into a sequential stream.”
So even if you write:
products.parallelStream().map(...)
If that stream is returned inside a flatMap(), Java will implicitly make it sequential again — effectively canceling your parallelism. 😬
I highly recommend checking out aleatorio.dev.br’s full post (I’ll link it in the comments).
✅ The Fix: Flip the Streams
Instead of looping over users and creating parallel streams of products, loop over the products:
List<String> result = products.parallelStream()
.flatMap(product ->
users.stream()
.map(user -> {
System.out.println("Parallel map: " + user + " - " + product + " on " + Thread.currentThread().getName());
return user + " → " + product;
})
)
.toList();
Now the outer stream is parallel — and that’s what matters.
🎉 Result
After flipping the stream:
- Threads used: ✅ yes
- CPU utilization: ✅ yes
- Job speed: ✅ improved
- Logs: showed lots of worker threads doing the job in parallel
It just took one line change to go from single-threaded sadness to full multicore glory. In my particular case, my process time went down from 45 min to 10 min!
✅ TL;DR
-
.parallelStream()
only works if the stream itself is parallel - Putting
.parallelStream()
inside a.flatMap()
from a sequential stream won’t help - Flip the loop: parallelize the outer stream, not the inner one
- Print
Thread.currentThread().getName()
to debug what’s really happening
Did this help you? Hit ❤️, drop a comment, or share your own gotchas with Java streams!
Top comments (0)