🎓 A1Learner
🔍
0 of 30 lessons completed

Java Parallel Streams

A parallel stream splits the work of a stream across threads. The split changes how the work runs, and the safe exhibits in this lesson print only results that stay the same either way.

Sequential and parallel sums print the same total

The same list of numbers from 1 to 1000 is summed twice, once in sequence and once in parallel. Both printed totals are the same number.

import java.util.ArrayList;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = new ArrayList<>();
    for (int i = 1; i <= 1000; i++) {
      numbers.add(i);
    }
    int sequential = numbers.stream()
        .mapToInt(Integer::intValue)
        .sum();
    int parallel = numbers.parallelStream()
        .mapToInt(Integer::intValue)
        .sum();
    System.out.println(sequential);
    System.out.println(parallel);
  }
}

A sorted print matches the sequential form

A parallel map uppercases each name, and the collected list is sorted before printing. The sorted parallel lines match the sorted sequential lines above them.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    List<String> names = List.of("Cara", "Ana", "Dan", "Ben");
    List<String> sequential = names.stream()
        .map(String::toUpperCase)
        .sorted()
        .toList();
    sequential.forEach(System.out::println);
    List<String> parallel = new ArrayList<>(names.parallelStream()
        .map(String::toUpperCase)
        .collect(Collectors.toList()));
    Collections.sort(parallel);
    parallel.forEach(System.out::println);
  }
}

A stateless map stays exact in parallel

Doubling a number reads only that number, so the map is stateless and safe in parallel. The doubled values are sorted before printing, so the lines have a fixed order.

import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = List.of(5, 2, 8, 1);
    List<Integer> doubled = numbers.parallelStream()
        .map(number -> number * 2)
        .sorted()
        .toList();
    doubled.forEach(System.out::println);
  }
}

Example

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = new ArrayList<>();
    for (int i = 1; i <= 1000; i++) {
      numbers.add(i);
    }
    int total = numbers.parallelStream()
        .mapToInt(Integer::intValue)
        .sum();
    System.out.println(total);
    List<String> names = List.of("Cara", "Ana", "Dan", "Ben");
    List<String> upper = new ArrayList<>(names.parallelStream()
        .map(String::toUpperCase)
        .collect(Collectors.toList()));
    Collections.sort(upper);
    upper.forEach(System.out::println);
  }
}

Key points

  • parallelStream asks the library to split a stream of a collection across threads.
  • Use only stateless operations in parallel work, meaning an operation that keeps no changing state of its own.
  • Shared mutation breaks parallel work, because two parts of the work can update the same place at the same time.
  • Order is not promised for parallel processing, so a sorted print after collecting makes the order a program choice.
  • A total is an order-free result, so a parallel sum prints the same total as a sequential sum.
  • Small inputs may run slower in parallel, because splitting the work adds a cost of its own.

In this example, a parallel sum prints the order-free total of 1 to 1000 first. A parallel map then uppercases four names, and sorting the collected list gives the names a fixed printed order.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

Which habit keeps parallel stream work safe?