Skip to content

Parallel Streams ​

🟑 MittelBearbeitet β˜‘οΈ13.03.2026

Zusammenfassung ​

Parallel Streams verarbeiten Daten gleichzeitig auf mehreren CPU-Kernen statt sequenziell. Sie nutzen automatisch das Fork/Join-Framework, um große Datenmengen schneller zu verarbeiten.

Kernkonzept ​

Parallel Streams teilen die Datenverarbeitung in mehrere Aufgaben auf und verteilen diese auf verfΓΌgbare Prozessorkerne. Das funktioniert transparent β€” du nutzt die gleiche API wie bei normalen Streams, musst aber .parallel() aufrufen.

Das Fork/Join-Framework kΓΌmmert sich um die Verwaltung von Threads und Task-Verteilung. Es teilt Daten rekursiv auf (Fork), verarbeitet sie parallel und kombiniert die Ergebnisse wieder (Join).

Achtung: Parallel Streams haben Overhead durch Thread-Management. Sie lohnen sich nur bei großen Datenmengen (typisch > 10.000 Elemente) oder aufwÀndigen Operationen.

Code-Beispiel ​

java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);

// Sequenziell (Standard)
int sum = numbers.stream()
    .filter(n -> n % 2 == 0)
    .map(n -> n * n)
    .reduce(0, Integer::sum);

// Parallel
int parallelSum = numbers.parallelStream()
    .filter(n -> n % 2 == 0)
    .map(n -> n * n)
    .reduce(0, Integer::sum);

// Oder mit .parallel()
int sum2 = numbers.stream()
    .parallel()
    .filter(n -> n % 2 == 0)
    .map(n -> n * n)
    .reduce(0, Integer::sum);

Wichtige Punkte ​

  • Thread-Pool: Nutzt den gemeinsamen ForkJoinPool.commonPool() β€” nicht zu viele parallele Streams gleichzeitig!
  • Reihenfolge: .parallel() kann die Verarbeitungsreihenfolge Γ€ndern β€” nicht geeignet, wenn Order wichtig ist
  • Stateless Operations: Verwende nur stateless Operationen (keine AbhΓ€ngigkeiten zwischen Elementen)
  • Overhead vs. Gewinn: Bei kleinen Listen ist parallel langsamer als sequenziell
  • Seiteneffekte vermeiden: Keine .forEach() mit Shared State β€” nutze stattdessen .collect()

Klassische Fragen ​

Wann sollte ich parallel Streams verwenden? ​

Bei großen Datenmengen (Richtlinie: > 10.000 Elemente) mit teuren Operationen und einer Verarbeitungslogik, die thread-safe und unabhÀngig für jedes Element ist. Bei kleinen Listen oder I/O-Operationen ist der Overhead grâßer als der Nutzen.


Warum ist my .forEach() mit parallel Streams unsicher? ​

.forEach() auf parallelen Streams kann zu Race Conditions fΓΌhren, wenn die Lambda externe State modifiziert. Nutze stattdessen .collect() mit einem thread-sicheren Collector, z.B. toList() oder toMap().


Kann ich die ParallelitΓ€t kontrollieren? ​

Nicht direkt ΓΌber Streams. Du kannst aber ein eigenes ForkJoinPool mit spezifischer ParallelitΓ€t erstellen und .execute() nutzen. FΓΌr die meisten FΓ€lle reicht der commonPool().


Wusstest du schon? ​

Das Fork/Join-Framework wurde ursprΓΌnglich von Doug Lea entwickelt und ist eine Meisterleistung der Concurrent Programming. Ein Parallel Stream auf einem Single-Core-System kann langsamer sein als der sequenzielle β€” aber die JVM wird nicht crashen. ParallelitΓ€t ist kein Allheilmittel, sondern erfordert sorgfΓ€ltige Messung mit JMH (Java Microbenchmark Harness)!