java Concurrency - Fork Join Framework
This Article describes fork join framework design and implementation
Fork join Framework supports a style of parallel programming in which Problems are solved by (recursively) splitting them into subtasks that are solved in parallel, waiting for them to complete, and then composing results.
Design
Fork/Join programs can be run using any framework that supports construction of subtasks that are executed in parallel, along with a mechanism for waiting out their completion.
Fork/Join task has its own characteristics:
- Fork/Join tasks have simple and regular synchronization and management requirements.
- do not need to block except to wait out subtasks
- Given reasonable base task granularity, the cost of constructing and managing a thread can be greater than the computation time of the task itself.
Design details:
- A pool of worker thread is established. Normally thread number equals to CPU number.
- All Fork/Join tasks are instances of a lightweight executable class,not instances of threads.
- A special purpose queuing and scheduling discipline is used to manage tasks and execute them via the worker threads. These mechanics are triggered by those few methods provided in the task class:
- fork
- join
- isDone
work-stealing
The heart of Fork/Join framework lies in its lightweight scheduling mechanics.
- Each worker thread maintains runnable tasks in its own scheduling queue.
- Queues are maintained as double-ended queues(deques),supporting both LIFO(stack operation push and pop), as well as FIFO (queue operation offer and poll)
- Subtasks generated in tasks run by a given worker thread are pushed onto that workers own deque.
- Worker threads process their own deques in LIFO order by popping tasks.
- Worker threads take(steal) a task from another workers using FIFO rule.
- When a worker thread encounters a join operation, it processes other tasks, if available, until the target task is noticed to have completed. All tasks otherwise run to completion without blocking.
- When a worker thread has no work and fails to steal any from others, it backs off and tries again later unless all workers are known to be similarly idle.
Implementation
ctl
bits and masks and bounds are packed with 4 16 bit subfields
1. RC Number of released workers
2. TC Number of total workers
3. SS version count and status of top waiting thread
4. ID poolIndex of top of Treiber stack of waiters
interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning)
boolean isCancelled()
boolean isDone()
V get()
V get(long timeout, TimeUnit unit)
default V resultNow()
default Throwable exceptionNow()
default State state()
}
abstract class ForkJoinTask<V> implements Future {
volatile int status
volatile Aux aux
}
class Aux {
Thread thread
final Throwable ex
Aux next
}
interface Executor {
void execute(Runnable command)
}
interface ExecutorService extends Executor, AutoCloseable {
<T> Future<T> submit(Callable<T> task)
void shutdown()
List<Runnable> shutdownNow()
boolean isShutdown()
boolean awaitTermination(long timeout, TimeUnit unit)
boolean isTerminated()
<T> List<Future<T>> invokeAll(tasks, timeout, unit)
<T> T invokeAny(tasks)
default void close()
}
abstract class AbstractExecutorService implements ExecutorService
class ForkJoinPool extends AbstractExecutorService {
{static} final ForkJoinPool common
{static} volatile int poolIds
volatile CountDownLatch termination
final Predicate<? super ForkJoinPool> saturate
final ForkJoinWorkerThreadFactory factory
final UncaughtExceptionHandler ueh
final SharedThreadContainer container
final String workerNamePrefix
WorkQueue[] queues
final long keepAlive
final long config
volatile long stealCount
volatile long threadIds
volatile int runState
volatile long ctl
int parallelism
}
class WorkQueue {
ForkJoinWorkerThread owner
ForkJoinTask<?>[] array
int base
int top
final int config
int phase
int stackPred
volatile int source
int nsteals
volatile int parking
ForkJoinTask<?> poll(ForkJoinPool pool)
void push(ForkJoinTask<?> task, ForkJoinPool pool,
boolean internal)
ForkJoinTask<?> nextLocalTask()
}
ForkJoinPool o-- WorkQueue
WorkQueue o-- ForkJoinTask
ForkJoinTask *-- Aux