Parallel streams and the common pool

Multithreading · lesson 23 of 38 · 4 min read

When .parallel() genuinely helps, which pool it borrows, and the traps that make it slower.

Open this lesson in the learning hub

Key points

  • .parallel() splits the source, runs the pipeline on several workers and merges the partial results.
  • It runs on the shared common pool, sized to cores minus one. One slow task in there stalls every other user of it.
  • Never do blocking I/O in a parallel stream. Give that work its own executor, or use virtual threads.
  • It pays off with a lot of data, cheap splitting and independent work. Arrays and ranges split well, LinkedList does not.
  • Encounter order still holds for ordered collectors, so the parallel answer matches the serial one exactly.
  • The lambdas must be stateless. Writing into a shared list from a parallel stream is a race you added yourself.

Example

import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) throws Exception {
        long serial = IntStream.rangeClosed(1, 1_000_000).asLongStream().map(n -> n * n).sum();
        long parallel = IntStream.rangeClosed(1, 1_000_000).parallel().asLongStream().map(n -> n * n).sum();
        System.out.println("serial     : " + serial);
        System.out.println("parallel   : " + parallel + " (split, mapped, merged)");

        List<String> ordered = IntStream.rangeClosed(1, 6).parallel()
                .mapToObj(n -> "v" + n)
                .toList();                                  // encounter order is still preserved
        System.out.println("ordered    : " + ordered);

        System.out.println("common pool: " + ForkJoinPool.commonPool().getParallelism() + " workers, shared by the whole JVM");

        ForkJoinPool own = new ForkJoinPool(2);              // keep slow work off the common pool
        long inOwnPool = own.submit(() -> IntStream.rangeClosed(1, 100).parallel().asLongStream().sum()).get();
        own.shutdown();
        System.out.println("own pool   : " + inOwnPool);
    }
}

Parallel streams suit big, CPU-bound, side-effect-free work. Measure before and after.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Multithreading course, and every lesson in it is listed on the Multithreading contents page.