Skip to content
閲覧中:
7. 並列Streamの深掘り (86-100)

7. 並列Streamの深掘り (86-100)

いよいよ最後のセクション、**並列Stream(Parallel Stream)の深掘り**です。Java Gold試験では、並列処理の仕組み(Fork/Join)がStream APIを通じてどのように適用されるか、その「ルールと限界」が問われます。

86番から100番まで、全項目を解説します。


86-89. 並列Streamの生成と集約

並列Streamでは、データの分割と結合のプロセスが重要になります。

Java
List<String> list = List.of("apple", "banana", "cherry");

// 86. parallelStream(): コレクションから直接作成
// 87. reduce(identity, accumulator, combiner): 並列用の3引数版
int totalLength = list.parallelStream().reduce(
    0,                                      // identity: 初期値
    (sum, s) -> sum + s.length(),           // accumulator: 各スレッド内の計算
    (sum1, sum2) -> sum1 + sum2             // 89. combiner: スレッド間の結果を結合
);

// 88. identityの制約: 
// 任意のxに対して op(identity, x) == x でなければならない(加算なら0、乗算なら1)

90-92. 順序とパフォーマンス

並列化すれば必ず速くなるわけではなく、順序の維持にはコストがかかります。

Java
// 90. 無限ストリームの並列化
// Stream.iterate(0, i -> i + 1).parallel().limit(10)...
// 無限ストリームを並列化すると、分割位置の計算が困難でパフォーマンスが落ちる場合がある

// 91. findAny() の利点
// findFirst()は「最初の要素」を特定するため並列でも順序を気にするが、
// findAny()は「最初に見つかったもの」を返すため、並列時に圧倒的に速い

// 92. unordered(): 順序の制約を外す
// distinct()やlimit()などの前に置くと、順序を守るためのオーバーヘッドが減り、並列処理が加速する
list.parallelStream().unordered().distinct().collect(Collectors.toList());

93-95. 分割の仕組み (Spliterator)

Streamの裏側で動いている分割用イテレータの知識です。

Java
// 93. spliterator(): ストリームを分割するためのオブジェクト
Spliterator<String> split1 = list.spliterator();

// 94. trySplit(): 自身を分割して新しいSpliteratorを返す
Spliterator<String> split2 = split1.trySplit(); 

// 95. characteristics(): 特性の確認
// ORDERED(順序あり), DISTINCT(重複なし), SORTED(ソート済み)など
int characteristics = split1.characteristics();

96-98. 実行環境と副作用

スレッドがどのように動くか、そのルールについてです。

  • 96. 副作用(Side Effects)の禁止: 並列Stream内で外部の変数(非スレッドセーフなListなど)を add するのは厳禁です。結果が不整合になります。
  • 97. I/O ボトルネック: System.out.println は内部で同期化されているため、並列Stream内で多用すると並列化のメリットが消えます。
  • 98. 共通プール: 並列Streamはデフォルトで ForkJoinPool.commonPool() を使用します。スレッド数はCPUコア数に基づきます。

99-100. 発展的な非同期処理

Stream APIを超えた、Java 8以降の非同期連携です。

Java
// 99. ThreadLocal: スレッドごとに独立した値を保持する(並列処理でのデータ混線を防ぐ)
ThreadLocal<String> threadId = ThreadLocal.withInitial(() -> Thread.currentThread().getName());

// 100. CompletableFuture: 非同期処理を連鎖させる(Java Goldの試験範囲外だが関連知識)
CompletableFuture.supplyAsync(() -> "Hello")
                 .thenAccept(s -> System.out.println(s + " World"));

💡 Java Gold 試験対策:最後の「ひっかけ」ポイント

  1. reduceのCombinerが呼ばれない?: stream()(順次)で reduce の3引数版を使っても、combiner は実行されません。parallelStream() の時だけ登場します。
  2. ArrayList vs LinkedList: 並列Streamのソースとして ArrayList は優秀(真ん中でパカッと割れるから)ですが、LinkedList は分割にコストがかかるため並列化に向きません。
  3. stateful(状態あり)な中間操作: sorted(), distinct(), limit() は、全要素の状態を知る必要があるため、並列Stream内では非常にコストが高い操作になります。

お疲れ様でした!これで Java Stream API (100項目) および 並列処理 (100項目) の計200項目のノックが完了しました。

Java Gold試験の合格に向けて、次は**「本番形式の模擬試験(2分野ミックス)」**を作ってみますか?それとも、他の分野(IO/NIO、JDBC、例外処理など)のノックを開始しますか?