Fork Join in Java

Nowadays, systems are launching with multicore processors. The multicore processors make the computation faster. Hence, it becomes necessary for a programmer to use multicore processors effectively so that the result can be generated in less span of time. Fork/Join in Java is used to make use of the cores (brain of CPU that process the instructions) in an efficient manner. The fork/join splits a bigger task into smaller sub-tasks. These sub-tasks are then distributed among the cores. The results of these subtasks are then joined to generate the final result. The splitting of a task and joining the results imitates the divide-and-conquer algorithm. The fork is responsible for splitting the task, and join is responsible for merging the results of the task to generate the final result.

Fork Join in Java

It is worth noting here that various threads that are responsible for the completion of the sub-tasks never sit idle. In fact, they implement the work-stealing algorithm, where an idle thread steals the work from those threads that are busy.

Pseudocode

An important point to remember is that one should not be blindly splitting a problem into sub-problems. Splitting a problem into sub-problems has its overhead. If the overhead and the time consumed in solving the sub-problems is greater than solving the problem itself, then one should not be splitting the problem. The limit that makes logical sense to split a problem into subproblem is known as threshold.

Java Fork/Join Program

The following program illustrates the working of the fork/join in Java.

FileName: ForkJoinExample.java

Output:

The number 50 is found 5 times.

Explanation: In the code, we have extended the abstract class RecursiveTask. The compute() method of the class contains the computational code. The type parameter <Integer> of the class RecursiveTask determines what type of result is returned. The search task created with the help of the class Recursive class is submitted to the ForkJoinPool. When the invoke() method of the ForkJoinPool class is invoked, the task execution starts. The invoke() method combines the fork() as well as the join() method in the single call, and waits for the task execution to finish, and then returns the result. When the invoke() method is called it splits the task into subtasks.

Java ForkJoinPool Class

The center of the fork/join framework is the ForkJoinPool class. The ForkJoinPool class implements the ExecutorService interface. It also extends the AbstractExecutorService class and implements the work-stealing algorithm.

Methods of ForkJoinPool Class

MethodsDescription
public int getParallelism()The parallelism level of the pool is returned by this method.
public boolean isShutdown()If the pool invoking this method has been shut down, then the method returns true; otherwise; false.
public boolean isQuiescent()If all the worker threads of the pool remain idle, the method returns true otherwise false.
public boolean hasQueuedSubmissions()If any task submitted to the pool has not started its execution, then the method returns true; otherwise; false.
public int getPoolSize()Returns the total number of worker threads that have begun their execution but not finished their execution.
public long getStealCount()The method returns the total count of the number of tasks that have been stolen from the other worker thread.
public boolean isTerminating()If the process of termination has been started but not completed yet, then the method returns true, otherwise; false.
public int getActiveThreadCount()The method returns the total number of threads that are currently executing or stealing tasks from the other threads.
public long getQueuedTaskCount()The method returns the total number of tasks that are present in the queues by the worker threads.
public ForkJoinTask<?> submit(Runnable task)A Runnable task is submitted by this method for execution and returns the Future, which represents the task.
public List<Runnable> shutdownNow()The method tries to stop or cancel all tasks and reject all the following tasks.

Fork/Join Implementation

There are two ways to instantiate the ForkJoinClass.

1) Using the Constructor of the Class

ForkJoinPool(): It is the default constructor of the ForkJoinPool class. It creates a default pool. The generated pool supports parallelism that is equal to the total number of processors available in the system. In the above example, we have used this constructor to instantiate the ForkJoinPool class.

ForkJoinPool(int p): It is parameterized constructor that is also used to create a pool with customized parallelism. The value p must be a natural number (> 0) and should not exceed the number of processors available in the system.

2) Using the Static Method commonPool()

The static method commonPool() of the ForkJoinPool class can also be used to create an instance of the ForkJoinPool class.

Filename: JavaForkJoinPoolExample.java

Output:

Total Number of available cores in the system processor is: 4
Total number of active threads before invoking: 0
Total number of active threads after invoking: 3
The size of the Common Pool is: 3