All topics
streams
advanced

Parallel Streams

Switch a stream pipeline to run in parallel on the common ForkJoinPool — for CPU-bound work over large data.

A parallel stream takes the same pipeline you would write sequentially and runs it across multiple threads, splitting the data so several cores work on different chunks at once. You opt in with a single call — collection.parallelStream() or .parallel() on an existing stream — which makes it seductively easy, and that ease is precisely the trap: parallelism helps in a narrow set of conditions and silently hurts or corrupts results outside them.

A buffet line vs many self-serve stations. Faster if the food is ready and there's enough room — but useless if everyone needs to use the same fryer (a shared resource).

Key Concepts

1
Under the hood, a parallel stream uses the fork/join framework to recursively split the source into pieces (the spliterator decides how), processes each piece on the common ForkJoinPool, and then joins the partial results back together. For this to pay off you need several things at once: a large dataset, work per element that is genuinely CPU-bound and substantial, a source that splits cheaply and evenly (arrays and ArrayList split well; LinkedList and most I/O sources do not), and operations that combine associatively. When those hold, you can get a near-linear speedup on a multicore machine.
ForkJoinPoolArrayListLinkedList
2
The hazards are what interviewers focus on. The common pool is shared by the entire JVM and sized to the available cores, so putting blocking I/O on a parallel stream can starve every other parallel task in the process; isolate such work on a dedicated pool. Any shared mutable state touched from the pipeline is a data race — parallel streams demand stateless, side-effect-free lambdas. Operations that depend on encounter order (limit, findFirst) add coordination overhead, and a poor split or tiny dataset makes the thread-handoff cost exceed any benefit. The honest default is sequential; reach for parallel() only after measuring, with a large CPU-bound workload, and confirm it is actually faster.
limitfindFirstparallel()