モジュール java.base
パッケージ java.util.concurrent

クラスForkJoinTask<V>

java.lang.Object
java.util.concurrent.ForkJoinTask<V>
型パラメータ:
V - タスクの結果のタイプ
すべての実装されたインタフェース:
Serializable, Future<V>
直系の既知のサブクラス:
CountedCompleter, RecursiveAction, RecursiveTask

public abstract class ForkJoinTask<V> extends Object implements Future<V>, Serializable
ForkJoinPool内で実行する抽象基底クラスです。 ForkJoinTaskは、通常のスレッドよりはるかに軽量な、スレッドに似たエンティティです。 ある程度の使用制限を犠牲にして、ForkJoinPool内の少ない数の実際のスレッドで、膨大な数のタスクやサブタスクをホストできます。

メインのForkJoinTaskは、ForkJoinPoolに明示的に送信されたときに実行を開始します。ForkJoinの計算にまだ関与していない場合は、fork()invoke()または関連メソッドを介してForkJoinPool.commonPool()で開始されます。 起動されたあと、通常は次に、ほかのサブタスクを起動します。 このクラスの名前で示されているように、ForkJoinTaskを使用している多くのプログラムはfork()メソッドとjoin()メソッド、またはinvokeAllなどの派生メソッドのみを使用します。 ただし、このクラスはまた、高度な使用方法で効果を発揮するその他のいくつかのメソッドや、新しい形式の分岐/結合処理のサポートを可能にする拡張機能も提供します。

ForkJoinTaskは、軽量な形式のFutureです。 ForkJoinTaskの効率は、純粋な関数を計算するか、または純粋に切り離されたオブジェクトに対して動作するという、計算タスクとしての主要な使用方法を反映する(部分的に静的にしか強制できない)一連の制限から得られます。 主な調整メカニズムには、非同期実行を調整するfork()や、タスクの結果が計算されるまで処理を続行しないjoin()があります。 計算は、理想的にはsynchronizedメソッドまたはブロックを回避するべきであり、また他のタスクの結合や、分岐/結合スケジューリングと連携するために通知されるPhaserなどのシンクロナイザの使用を除き、その他の同期のブロックを最小限に抑えるべきです。 分割可能なタスクもまた、入出力のブロックを実行するべきではなく、また理想的には実行中の他のタスクからアクセスされる変数とは完全に独立している変数にアクセスするべきです。 これらのガイドラインは、IOExceptionsなどのチェック例外をスローできないようにすることによって、緩やかに適用されます。 ただし、計算では、結合しようとしている呼出し側に再スローされる非チェック例外が引き続き発生する可能性があります。 これらの例外には、さらに、内部タスク・キューの割当て失敗などの内部リソースの不足によって生成されるRejectedExecutionExceptionが含まれる可能性があります。 再スローされた例外は通常の例外と同じように動作しますが、可能な場合は、計算を開始したスレッドと実際に例外が発生しているスレッドの両方(最小限としては後者のみ)の(たとえば、ex.printStackTrace()を使用して表示された)スタック・トレースを含みます。

ブロックする可能性のあるForkJoinTasksを定義して使用できますが、これを行うにはさらに3つの考慮事項が必要です: (1) otherタスクが外部同期またはI/Oをブロックするタスクに依存する場合、少数の完了。 結合されないイベント形式の非同期タスク(たとえば、CountedCompleterをサブクラス化するもの)は、多くの場合このカテゴリに入ります。(2)リソースへの影響を最小限に抑えるには、タスクを小さくして、理想的には(おそらく)ブロック・アクションしか実行しないようにする必要があります。(3) ForkJoinPool.ManagedBlocker APIを使用しない場合や、ブロックされる可能性があるタスクの数がプールのForkJoinPool.getParallelism()のレベルより小さいことがわかっている場合、そのプールでは、処理の進行や良好なパフォーマンスを確保するだけの十分なスレッドが使用できることを保証できません。

完了を待機し、タスクの結果を抽出するための主要メソッドはjoin()ですが、いくつかのバリアントが存在します。Future.get()メソッドは、完了に対する割込み可能な待機または時間指定された待機、あるいはその両方をサポートし、Futureの規則を使用して結果を報告します。 invoke()メソッドは、意味的にはfork(); join()と同等ですが、常に現在のスレッドで実行を開始しようとします。 これらのメソッドの「非出力」形式は、結果を抽出せず、例外も報告しません。 これらは、一連のタスクが実行されていて、そのすべてが完了するまで結果または例外の処理を遅らせる必要がある場合に役立つことがあります。 invokeAllメソッド(複数のバージョンで使用可能)は、もっとも一般的な形式の並列呼出し、つまり一連のタスクのフォークと、そのすべての結合を実行します。

もっとも一般的な用途では、分岐/結合ペアが並列的な再帰関数からの呼出し(分岐)と復帰(結合)のように動作します。 他の形式の再帰呼出しと同様に、復帰(結合)はもっとも深いものを最初に実行する必要があります。 たとえば、a.fork(); b.fork(); b.join(); a.join();は、bの前にaを結合するより、かなり効率的である可能性があります。

タスクの実行ステータスは、いくつかの詳細レベルで照会することができます: isDone()は、タスクがなんらかの方法で(タスクが実行されずに取消された場合)で完了した場合にはtrueです。isCompletedNormally()は、取消しまたは例外が発生せずに完了した場合にはtrueです。isCancelled()は、タスクが(この場合、getException(boolean)CancellationExceptionを返します。)で取り消された場合にはtrueで、タスクが取り消された場合または例外が発生した場合にはisCompletedAbnormally()がtrueです。この場合、getException(boolean)は、検出された例外またはCancellationExceptionを返します。

ForkJoinTaskクラスは通常、直接にはサブクラス化されません。 かわりに、特定のスタイルの分岐/結合処理をサポートする抽象クラスのいずれかをサブクラス化します。これは通常、結果を返さないほとんどの計算の場合はRecursiveAction、結果を返す計算の場合はRecursiveTask、完了したアクションが他のアクションをトリガーする計算の場合はCountedCompleterです。 通常、具象ForkJoinTaskサブクラスは、コンストラクタで確立されたパラメータから成るフィールドを宣言してから、この基底クラスによって提供される制御メソッドを何らかの方法で使用するcomputeメソッドを定義します。

join()メソッドとそのバリアントが使用に適しているのは、完了の依存関係が非循環式である場合、つまり、並列計算を無閉路有向グラフ(DAG)として記述できる場合だけです。 それ以外の場合は、タスクが循環的に互いを待機するため、実行によってある種のデッドロックが発生する可能性があります。 ただし、このフレームワークでは、DAGとして静的に構造化されない問題のためのカスタム・サブクラスの構築に役立つ可能性のあるその他のメソッドや手法(たとえば、PhaserhelpQuiesce()、およびcomplete(V)の使用)がサポートされています。 このような用途をサポートするため、setForkJoinTaskTag(short)またはcompareAndSetForkJoinTaskTag(short, short)を使用してForkJoinTaskをshort値で原子的にタグ付けし、getForkJoinTaskTag()を使用して確認できます。 ForkJoinTaskの実装では、これらのprotectedメソッドまたはタグはどのような目的にも使用されませんが、特化されたサブクラスを構築するときに役立つ可能性があります。 たとえば、並列的なグラフのトラバースでは、指定されたメソッドを使用して、すでに処理されているノードまたはタスクの再チェックを回避できます。 (タグ付けのメソッド名は部分的に大きくなるため、それぞれの使用パターンを反映したメソッドを定義することをお薦めします。)

基本となる軽量タスク・スケジューリング・フレームワークに本質的に結び付けられた実装のオーバーライドを回避するために、ほとんどの基本サポート・メソッドはfinalです。 新しい基本的なスタイルの分岐/結合処理を作成している開発者は、protectedメソッド、exec()setRawResult(V)、およびgetRawResult()の実装を最小限にする一方で、そのサブクラスで(おそらく、このクラスによって提供されるほかのprotectedメソッドを使用して)実装できる抽象計算メソッドも導入するようにしてください。

ForkJoinTaskでは、比較的少ない量の計算を実行するようにしてください。 大きなタスクは、通常は再帰的分解を使用して、より小さなサブタスクに分割するようにしてください。 非常に大まかな経験則として、1つのタスクでは100より多く10000より少ない基本的な計算ステップを実行するようにし、無期限ループを回避するようにしてください。 タスクが大きすぎると、並列性によってスループットを向上させることができません。 小さすぎると、メモリーや内部タスク保守のオーバーヘッドによって処理効率が低下する可能性があります。

このクラスは、ForkJoinTasksの実行をほかの種類のタスクと混在させるときに役立つ可能性のある、RunnableおよびCallableのためのadaptメソッドを提供します。 すべてのタスクがこの形式である場合は、asyncModeで構築されたプールの使用を検討してください。

ForkJoinTaskはSerializableです。これにより、リモート実行フレームワークなどの拡張機能で使用できるようになります。 タスクの直列化は、実行中ではなく、実行の前またはあとにのみ行うのが適切です。 実行中は直列化自体が使用されません。

導入されたバージョン:
1.7
関連項目: