6. Fork/Join フレームワーク (71-85)
Fork/Join フレームワークは、大きなタスクを小さなサブタスクに分割(Fork)し、それぞれの結果を統合(Join)して最終的な答えを出す「分割統治法」を並列で行うための仕組みです。Java Gold試験では、**クラスの継承関係とメソッドの呼び出し順序**が頻出します。
71番から85番までの項目をすべて網羅して解説します。
71-73. Fork/Join の主要クラス¶
タスクの種類によって継承するクラスを使い分けます。
Java
// 71. ForkJoinPool: タスクを実行する専用のプール
ForkJoinPool pool = new ForkJoinPool();
// 72. RecursiveTask<V>: 戻り値があるタスク (V型を返す)
class SumTask extends RecursiveTask<Long> { ... }
// 73. RecursiveAction: 戻り値がないタスク (void)
class PrintTask extends RecursiveAction { ... }
74-77. 基本的なメソッドと処理の流れ¶
試験で最も問われる「再帰処理」のテンプレートコードです。
Java
class MyTask extends RecursiveTask<Integer> {
private final int n;
MyTask(int n) { this.n = n; }
// 74. compute(): タスクのメインロジックを記述するメソッド
@Override
protected Integer compute() {
if (n <= 10) { // 79. 閾値(これ以上分割しない基準)
return n * 2;
}
// 75. fork(): サブタスクを別スレッドで非同期に実行開始
MyTask subTask = new MyTask(n - 10);
subTask.fork();
// 76. join(): サブタスクの完了を待ち、結果を受け取る
// 77. invoke(): 最初の一歩としてプールにタスクを投げる際にも使われる
return n * 2 + subTask.join();
}
}
78-80. 実行の仕組みとプール¶
内部的な動きとパフォーマンスに関する項目です。
- 78. ワークスティーリング (Work-Stealing): 自分のタスクが終わって暇になったスレッドが、他の忙しいスレッドのタスク行列の「後ろ」からタスクを盗んで実行する仕組み。これにより効率を最大化します。
- 79. 閾値 (Threshold): タスクをこれ以上分割するとオーバーヘッドが大きすぎるという「止め時」の設定。
- 80. commonPool(): 明示的に
new ForkJoinPool()しなくても、ForkJoinPool.commonPool()で共有のプールを取得できます。
81-85. 注意点と応用¶
- 81. 呼び出し順序の罠: 試験では
sub1.fork(); sub2.fork(); sub2.join(); sub1.join();という順序がよく出ます。これなら並列に走りますが、sub1.fork(); sub1.join();と書くと逐次処理(シングルスレッド)と同じになってしまいます。 - 82. 実行時例外:
RecursiveTask内で例外が起きると、join()を呼んでいる側でExecutionExceptionなどがスローされます。 - 83. invokeAll(): 複数のタスクを一度にフォークし、すべて終わるまで待機する便利なメソッド。
- 84. 戻り値の型:
RecursiveTask<V>のVは、クラス宣言時の型パラメータと一致している必要があります。 - 85. 並列数のデフォルト: デフォルトでは
Runtime.getRuntime().availableProcessors() - 1のスレッドが使われます。
💡 Java Gold 試験対策の「急所」¶
- 戻り値があるかないか?:
-
問題文のコードが
RecursiveTaskなのにcompute()の戻り値がvoidだったり、逆にRecursiveActionなのにreturnしていたら即座にコンパイルエラーと判断してください。 -
fork()とjoin()の位置: -
join()は「結果が必要になる直前」に呼びます。fork()してすぐjoin()するのは並列化の失敗パターン(ひっかけ)です。 -
どのメソッドをオーバーライドするか?:
- 必ず
compute()です。run()やcall()ではありません。
これで並列処理の技術的な核心部分はほぼ網羅しました! 最後は、「86-100. 並列Streamの深掘り」 です。ここまでの「並列の仕組み」が Stream API とどう融合するかを仕上げます。準備はいいですか?