0Pricing
Java Academy · レッスン

並列ストリームの作成

parallel() と parallelStream() です。

「並列ストリームの作成」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

並列ストリームの動作

並列ストリームはデータを分割し、複数のスレッドでチャンクを処理してから結果を結合します。目的は大規模な処理でスループットを向上させることです。

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int sum = IntStream.rangeClosed(1, 1000)
            .parallel()
            .sum();
        System.out.println(sum);
    }
}

既存のストリームに対する parallel()

parallel() を呼び出すと、逐次ストリームが並列ストリームに変わります。パイプラインのどこにでも配置できます。

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> nums = List.of(1, 2, 3, 4, 5);
        int total = nums.stream()
            .parallel()
            .mapToInt(Integer::intValue)
            .sum();
        System.out.println(total);
    }
}

コレクションに対する parallelStream()

Collection.parallelStream() は並列ストリームを直接作成します。stream().parallel() を簡略化したものです。

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> words = List.of("a", "bb", "ccc");
        int chars = words.parallelStream()
            .mapToInt(String::length)
            .sum();
        System.out.println(chars);
    }
}

逐次実行に戻す

sequential() はストリームを単一スレッド実行に戻します。パイプライン全体では、parallel() または sequential() の最後の呼び出しが有効になります。

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int sum = IntStream.rangeClosed(1, 100)
            .parallel()
            .sequential()
            .sum();
        System.out.println(sum);
    }
}

isParallel の確認

isParallel() は、ストリームが並列実行されるかどうかを示します。

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        System.out.println(IntStream.range(0, 10).isParallel());
        System.out.println(IntStream.range(0, 10).parallel().isParallel());
    }
}

結果は同じ、実行方法は異なる

合計のような結合的な演算では、並列ストリームと逐次ストリームは同じ結果を返します。異なるのは実行方法だけです。

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int seq = IntStream.rangeClosed(1, 50).sum();
        int par = IntStream.rangeClosed(1, 50).parallel().sum();
        System.out.println(seq == par);
    }
}

共通 ForkJoinPool

並列ストリームは共有された ForkJoinPool.commonPool() を使用します。デフォルトのサイズは、利用可能なプロセッサ数から1を引いた数です。

public class Main {
    public static void main(String[] args) {
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

スレッドの順序は保証されない

forEach では、チャンクの完了するタイミングが異なるため、並列ストリームが任意の順序で出力することがあります。順序が重要な場合は forEachOrdered を使用します。

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        IntStream.rangeClosed(1, 5)
            .parallel()
            .forEachOrdered(System.out::println);
    }
}

縮約で部分結果を結合する

内部では、並列縮約によってチャンクごとの部分結果が計算され、コンバイナーで結合されます。正しく動作させるには、演算が結合的でなければなりません。

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int product = IntStream.rangeClosed(1, 6)
            .parallel()
            .reduce(1, (a, b) -> a * b);
        System.out.println(product);
    }
}

並列での収集

コレクターフレームワークは、部分コンテナを結合することで並列収集をサポートします。groupingBy は並列でも正しく動作します。

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> words = List.of("apple", "banana", "avocado", "cherry");
        Map<Character, List<String>> byFirst = words.parallelStream()
            .collect(Collectors.groupingBy(w -> w.charAt(0)));
        System.out.println(byFirst);
    }
}

すべてのストリームが高速になるわけではない

並列化への切り替えは簡単ですが、常に有利とは限りません。データセットが小さい場合や処理が軽い場合は、分割と結合のオーバーヘッドによって並列のほうが遅くなることがあります。

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long count = IntStream.rangeClosed(1, 10)
            .parallel()
            .filter(n -> n % 2 == 0)
            .count();
        System.out.println(count);
    }
}

確認問題

並列ストリームをデフォルトで実行するスレッドプールはどれですか。

まとめ

並列ストリームを作成しました。

  • parallel() は任意のストリームを変換し、parallelStream() はコレクション向けの簡略形です。
  • sequential() で元に戻せます。最後の呼び出しが有効になります。
  • 共有された ForkJoinPool.commonPool() 上で実行されます。
  • 結合的な演算では逐次実行と結果が一致しますが、順序と速度は保証されません。

よくある質問

「並列ストリームの作成」レッスンは無料ですか?

はい。「並列ストリームの作成」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「並列ストリームの作成」で何を学びますか?

parallel() と parallelStream() です。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「並列ストリームの作成」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 並列ストリームの作成
  2. 並列処理が役立つ場合
  3. スレッド安全性と副作用
  4. よくある落とし穴
← Java Academyに戻る