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:
<span>List</span><span><</span><span>String</span><span>></span> <span>users</span> <span>=</span> <span>List</span><span>.</span><span>of</span><span>(</span><span>"alice"</span><span>,</span> <span>"bob"</span><span>);</span><span>List</span><span><</span><span>String</span><span>></span> <span>products</span> <span>=</span> <span>IntStream</span><span>.</span><span>range</span><span>(</span><span>0</span><span>,</span> <span>10_000</span><span>)</span><span>.</span><span>mapToObj</span><span>(</span><span>i</span> <span>-></span> <span>"product-"</span> <span>+</span> <span>i</span><span>)</span><span>.</span><span>toList</span><span>();</span><span>List</span><span><</span><span>String</span><span>></span> <span>result</span> <span>=</span> <span>users</span><span>.</span><span>stream</span><span>()</span><span>.</span><span>flatMap</span><span>(</span><span>user</span> <span>-></span><span>products</span><span>.</span><span>parallelStream</span><span>()</span><span>.</span><span>map</span><span>(</span><span>product</span> <span>-></span> <span>{</span><span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Sequential map: "</span> <span>+</span> <span>user</span> <span>+</span> <span>" - "</span> <span>+</span> <span>product</span> <span>+</span> <span>" on "</span> <span>+</span> <span>Thread</span><span>.</span><span>currentThread</span><span>().</span><span>getName</span><span>());</span><span>return</span> <span>user</span> <span>+</span> <span>" → "</span> <span>+</span> <span>product</span><span>;</span><span>})</span><span>)</span><span>.</span><span>toList</span><span>();</span><span>List</span><span><</span><span>String</span><span>></span> <span>users</span> <span>=</span> <span>List</span><span>.</span><span>of</span><span>(</span><span>"alice"</span><span>,</span> <span>"bob"</span><span>);</span> <span>List</span><span><</span><span>String</span><span>></span> <span>products</span> <span>=</span> <span>IntStream</span><span>.</span><span>range</span><span>(</span><span>0</span><span>,</span> <span>10_000</span><span>)</span> <span>.</span><span>mapToObj</span><span>(</span><span>i</span> <span>-></span> <span>"product-"</span> <span>+</span> <span>i</span><span>)</span> <span>.</span><span>toList</span><span>();</span> <span>List</span><span><</span><span>String</span><span>></span> <span>result</span> <span>=</span> <span>users</span><span>.</span><span>stream</span><span>()</span> <span>.</span><span>flatMap</span><span>(</span><span>user</span> <span>-></span> <span>products</span><span>.</span><span>parallelStream</span><span>()</span> <span>.</span><span>map</span><span>(</span><span>product</span> <span>-></span> <span>{</span> <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Sequential map: "</span> <span>+</span> <span>user</span> <span>+</span> <span>" - "</span> <span>+</span> <span>product</span> <span>+</span> <span>" on "</span> <span>+</span> <span>Thread</span><span>.</span><span>currentThread</span><span>().</span><span>getName</span><span>());</span> <span>return</span> <span>user</span> <span>+</span> <span>" → "</span> <span>+</span> <span>product</span><span>;</span> <span>})</span> <span>)</span> <span>.</span><span>toList</span><span>();</span>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();
Enter fullscreen mode Exit fullscreen mode
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:
<span>products</span><span>.</span><span>parallelStream</span><span>().</span><span>map</span><span>(...)</span><span>products</span><span>.</span><span>parallelStream</span><span>().</span><span>map</span><span>(...)</span>products.parallelStream().map(...)
Enter fullscreen mode Exit fullscreen mode
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:
<span>List</span><span><</span><span>String</span><span>></span> <span>result</span> <span>=</span> <span>products</span><span>.</span><span>parallelStream</span><span>()</span><span>.</span><span>flatMap</span><span>(</span><span>product</span> <span>-></span><span>users</span><span>.</span><span>stream</span><span>()</span><span>.</span><span>map</span><span>(</span><span>user</span> <span>-></span> <span>{</span><span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Parallel map: "</span> <span>+</span> <span>user</span> <span>+</span> <span>" - "</span> <span>+</span> <span>product</span> <span>+</span> <span>" on "</span> <span>+</span> <span>Thread</span><span>.</span><span>currentThread</span><span>().</span><span>getName</span><span>());</span><span>return</span> <span>user</span> <span>+</span> <span>" → "</span> <span>+</span> <span>product</span><span>;</span><span>})</span><span>)</span><span>.</span><span>toList</span><span>();</span><span>List</span><span><</span><span>String</span><span>></span> <span>result</span> <span>=</span> <span>products</span><span>.</span><span>parallelStream</span><span>()</span> <span>.</span><span>flatMap</span><span>(</span><span>product</span> <span>-></span> <span>users</span><span>.</span><span>stream</span><span>()</span> <span>.</span><span>map</span><span>(</span><span>user</span> <span>-></span> <span>{</span> <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>"Parallel map: "</span> <span>+</span> <span>user</span> <span>+</span> <span>" - "</span> <span>+</span> <span>product</span> <span>+</span> <span>" on "</span> <span>+</span> <span>Thread</span><span>.</span><span>currentThread</span><span>().</span><span>getName</span><span>());</span> <span>return</span> <span>user</span> <span>+</span> <span>" → "</span> <span>+</span> <span>product</span><span>;</span> <span>})</span> <span>)</span> <span>.</span><span>toList</span><span>();</span>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();
Enter fullscreen mode Exit fullscreen mode
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!
原文链接:Why Your `.parallelStream()` Might Not Be Parallel at All
暂无评论内容