Why Your `.parallelStream()` Might Not Be Parallel at All

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

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
Time such as water, always silent. If you are well, it is sunny.
时光如水,总是无言。若你安好,便是晴天
评论 抢沙发

请登录后发表评论

    暂无评论内容