0

私はJavaのForkJoinTask.

JavaFutureTaskはテンプレート メソッドを提供しますdone()このメソッドをオーバーライドすると、「完了ハンドラの登録」が可能になります

の完了ハンドラを登録することは可能ForkJoinTaskですか?

アプリケーションでブロッキング スレッドを使用したくないので質問していますが、result = ForkJoinPool.invoke(myForkJoinTask)またはの呼び出しを介して計算結果を取得するとすぐに、アプリケーションでブロッキング スレッドが使用されますresult = ForkJoinPool.submit(myForkJoinTask).get()

4

1 に答える 1

1

「ロックフリー」プログラミングを意味していると思いますhttp://en.wikipedia.org/wiki/Non-blocking_algorithm ? FutureTask.get() は現在のスレッドをブロックする可能性があります (そのため、アイドル状態の CPU が残ります) が、ForkJoinTask.get() (または結合) は CPU をビジー状態に保とうとします。

これは、問題を多くの小さなピース (ForkJoinTask) に分割できる場合にうまく機能します。1 つの FJTask が他のタスクの結果を内部的に待っている場合、それは準備ができていません。ForkJoinTask は、実行する他の作業 (タスク) をその ForkJoinPool から取得しようとし、その間にそのタスクを実行します。

すべてのタスクが CPU バウンドになるまで、問題なく動作します。すべての CPU はビジー状態のままです。タスクのいずれかが何らかの外部イベントを待機している場合 (つまり、火星探査車に REST 呼び出しを送信している場合) は機能しません。また、問題はDAGを形成する必要があります。そうしないと、デッドロックが発生する可能性があります。ただし、同じタスクで以前に分岐したタスクのみに参加するまでは、うまく機能します。最後に分岐したタスクに参加するとさらに良いでしょう。

したがって、タスク内/タスク間で get() または join() を呼び出すことはそれほど悪くありません。

問題を解決するために完了ハンドラーについて言及しました。ForkJoinTask を自分で実装している場合は、RecursiveTask または RecursiveAction を参照してください。compute() を実装すると、各タスクの結果を返す代わりに、compute() 関数の最後にあるコレクターに簡単に転送できます。

ただし、コレクターが同時に呼び出されることを考慮する必要があります。値の追加または完了カウントのカウントについては、java.util.concurrent.atomicを参照してください。同期ブロックの使用は避けてください。そうしないと、すべてのタスクがこの単一のボトルネックを待つ必要があり、1 つの CPU のみが動作し続けます。

結果の伝播には、結果を返すよりも多くの問題が伴うと思います (FJPool がこれを処理するため)。さらに、最終結果がどの時点で完了したかを決定する (および外部に伝達する) ことが難しくなります。

于 2013-10-09T14:49:35.060 に答える