What is the use of Fork-join framework in Java?

Fork-Join overview

This is a framework that provides the user with tools to speed up the parallel processing of data handled by Java. The framework works on the concepts of divide and conquer where a single big task is effectively done by dividing it into smaller subtasks and solving these subtasks recursively. This takes advantage of the multiple cores of a processor and distributes the workload between the cores to finish up the task faster.

Just as the name suggests, the Fork-Join framework first forks the task, solves each subtask and then joins the results of the independent tasks to form a single output.

If a task does not have any output, i.e., has a void return type, then the framework performs the first half of the work mentioned above and only splits the tasks and solves them; there is no joining happening here.

Core classes in the Fork-Join framework

Following are core classes that are present inside java.util.concurrent:

  • ForkJoinPool: This is the center of the Fork-Join framework. ForkJoinPool is an ExecutorService used to manage and monitor worker threads, with each worker thread handling a single task.

  • ForkJoinTask: This is the abstract or the base type of all the tasks that run in the ForkJoinPool.

  • RecursiveTask: This is basically a subclass of ForkJoinTask where the compute method (the method where the task’s logic is defined) returns a value. These return values from each subtask are collected and joined to form the final output.

  • RecursiveAction: This is basically a subclass of ForkJoinTask where the compute method (the method where the task’s logic is defined) does not return a value. Spo the framework does not have to join any outputs and waits for all the subtasks to finish executing.

Example

In the following example, we try to determine the sum of the first 1000 natural numbers using the Fork-Join framework.

In our file Sum_ForkJoin.java, we first import java.util.concurrent.ForkJoinPool containing all the required classes and create a new ForkJoinPool, after which we create an array with the first 1000 numbers and pass it to our divide_solve function that we have made. This is basically the recursive division step where subtasks are created from bigger tasks. In the divide_solve.java file, we make a RecursiveTask named divide_solve, which keeps on splitting arrays recursively until there are less than or equal to 20 elements per array and then calls the summing function stored in the Sum_func.java file on it.

The functions that extend the class RecursiveTask need to be overridden using the @Override keyword. This allows the user to create their own custom functionality for the recursive task they are creating. This can be seen in both the Sum_func function and the divide_solve function.

Sum_ForkJoin.java
divide_solve.java
Sum_func.java
import java.util.concurrent.ForkJoinPool;
public class Sum_ForkJoin
{
static ForkJoinPool sum_pool = new ForkJoinPool();
public static void main(String[] args)
{
int [] BigTask_para = new int[1000];
for(int i=0; i<1000; i++)
{
BigTask_para[i] = i;
}
int BigOutput = sum_pool.invoke(new divide_solve(BigTask_para));
System.out.println("Sum of the first 800 numbers: " + BigOutput);
}
}

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved