Parallel Streams

How They Work

parallelStream() or .parallel() splits the data into chunks, processes them on the common ForkJoinPool (one thread per CPU core minus one, plus the caller) and combines the results.

[1 .. 1,000,000]
     │ split
 ┌───┴────┐
[1..500k] [500k..1M]     ← processed on different cores
 │ split    │ split
 ...        ...
     └──┬───┘ combine (sum)
      result

Order and Results

Example

Results like sums and toList() keep the correct order. forEach on a parallel stream prints in random order, so use forEachOrdered when order matters.

import java.util.*;
import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        long serial = LongStream.rangeClosed(1, 2_000_000).filter(n -> n % 3 == 0).sum();
        long parallel = LongStream.rangeClosed(1, 2_000_000).parallel().filter(n -> n % 3 == 0).sum();
        System.out.println("Same result: " + (serial == parallel) + " (" + parallel + ")");

        List<Integer> doubled = IntStream.rangeClosed(1, 10).parallel().map(n -> n * 2).boxed().toList();
        System.out.println("toList keeps encounter order: " + doubled);

        System.out.print("forEachOrdered: ");
        IntStream.rangeClosed(1, 10).parallel().forEachOrdered(n -> System.out.print(n + " "));
        System.out.println();
    }
}

Output

Same result: true (666666333333)
toList keeps encounter order: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
forEachOrdered: 1 2 3 4 5 6 7 8 9 10

When to Use

Good fitBad fit
Large data (100k+ elements), CPU-heavy work per elementSmall lists: thread overhead is bigger than the gain
ArrayList, arrays, IntStream.range (split easily)LinkedList, Stream.iterate (split badly)
Stateless, independent operationsShared mutable state, synchronized blocks
Associative reductions (sum, max)Blocking I/O (database, HTTP calls) — use an executor or virtual threads

Note: Never add to an ArrayList from a parallel forEach: it is not thread-safe and you will lose elements or get exceptions. Use collect / toList() instead. Always measure before and after switching to parallel.