![]() | |
|
New in the Java SE 7 release, the fork/join framework is an implementation of the ExecutorService
interface that helps you take advantage of
multiple processors. It is designed for work that can be broken into smaller pieces recursively. The goal is to use all the available processing power to
enhance the performance of your application.
As with any ExecutorService
, the fork/join framework distributes tasks to worker threads in a thread pool. The fork/join framework is distinct
because it uses a work-stealing algorithm. Worker threads that run out of things to do can steal tasks from other threads that are still busy.
The center of the fork/join framework is the ForkJoinPool
class, an extension of AbstractExecutorService
. ForkJoinPool
implements the core work-stealing algorithm and can execute ForkJoinTask
s.
Basic use
Using the fork/join framework is simple. The first step is to write some code that performs a segment of the work. Your code should look similar to this:
if (my portion of the work is small enough) do the work directly else split my work into two pieces invoke the two pieces and wait for the results
Wrap this code as a ForkJoinTask
subclass, typically as one of its more specialized types RecursiveTask
(which can return a result)
or RecursiveAction
.
After your ForkJoinTask
is ready, create one that represents all the work to be done and pass it to the invoke()
method of a
ForkJoinPool
instance.
Parallelism support
The core Java 7 fork/join addition is a new ForkJoinPool
executor that is dedicated to running instances implementing ForkJoinTask
.
ForkJoinTask
objects support the creation of subtasks plus waiting for the subtasks to complete. With those clear semantics, the executor is able
to dispatch tasks among its internal threads pool by "stealing" jobs when a task is waiting for another task to complete and there are pending tasks to be run.
ForkJoinTask
objects feature two specific methods:
The fork()
method allows a ForkJoinTask
to be planned for asynchronous execution. This allows a new
ForkJoinTask
to be launched from an existing one.
In turn, the join()
method allows a ForkJoinTask
to wait for the completion of another one.
Cooperation among tasks happens through fork()
and join()
, as illustrated in figure below. Note that the
fork()
and join()
method names should not be confused with their POSIX counterparts with which a process can
duplicate itself. There, fork()
only schedules a new task within a ForkJoinPool
, but no child Java Virtual
Machine is ever created.
There are two types of ForkJoinTask
specializations:
Instances of RecursiveAction
represent executions that do not yield a return value.
In contrast, instances of RecursiveTask
yield return values.
In general, RecursiveTask
is preferred because most divide-and-conquer algorithms return a value from a computation over
a data set. For the execution of tasks, different synchronous and asynchronous options are provided, making it possible to implement
elaborate patterns.
![]() ![]() ![]() |