Difference Between Fork/Join Framework and ExecutorService in Java
Last Updated :
18 Jul, 2022
The Fork/Join framework provides fine-grained task execution framework with high performance for Java data parallelism. Its parallel computing engine is used by many higher-level frameworks. The fork/join framework supports a style of parallel programming that solves problems by "Divide and conquer”, in the following manner as shown below:
- Splitting a task into sub-tasks.
- Solving sub-tasks in parallel
- Sub-tasks can run in parallel on different cores.
- Sub-tasks can also run concurrently in different threads on a single core.
- Waiting for them to complete
- join() waits for a sub-task to finish
- Merging the results.
- A task uses calls to join() to merge the sub-task results together.
Java Fork-Join Pool Computation Model
If a task does not return a result then it just waits for its sub-tasks to complete.
Below is a Java program to demonstrate the working of Fork/Join Framework :
Java
// Java program to demonstrate the working of Fork/Join
// Framework
// Importing required libraries
import java.io.*;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
// Class 1
// helper class
class SearchTask extends RecursiveTask<Integer> {
// Global variables
int array[];
int start, end;
int searchElement;
// Constructor for initialising globals
public SearchTask(int array[], int start, int end,
int searchElement)
{
// This keyword refers to current object itself
this.array = array;
this.start = start;
this.end = end;
this.searchElement = searchElement;
}
// Method
// @Override
protected Integer compute()
{
// Returns the count computed by processSearch
return processSearch();
}
// Method
// To count the count of searched element
private Integer processSearch()
{
// Initially count is set to zero
int count = 0;
// iterating using for loop
for (int i = start; i <= end; i++) {
// if element is present in array
if (array[i] == searchElement) {
// Increment the count
count++;
}
}
// Returning the count of searched element
return count;
}
}
// Class 2
// Main class
public class GFG {
// main driver method
public static void main(String args[])
{
// Custom input array elements
int array[] = { 1, 2, 6, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 6 };
// Custom element to be searched in array
int searchElement = 6;
// initializing starting and ending indices
int start = 0;
int end = array.length - 1;
// Creating object of ForkJoinPool class
ForkJoinPool pool = ForkJoinPool.commonPool();
// Now creating object of above class
SearchTask task = new SearchTask(array, start, end,
searchElement);
int result = pool.invoke(task);
// Print and display the searched element
// If found do display out the number of times it is
// found
System.out.println(searchElement + " found "
+ result + " times ");
}
}
Now dwelling onto The Java ExecutorService interface extends Executor so we get the one and only execute(Runnable) method defined by Executor. There are a lot more methods in Java ExecutorService compared to Java Executor. Some of the methods in the ExecutorService interface can be used to submit one or more tasks and returns something called a future(essentially a proxy to the result of a computation that runs concurrently and or asynchronously in the background).
The ExecutorService works in the following manner as follows:
- Submit 1+ tasks and return futures for these tasks.
- Manage the lifecycle of tasks and executor service itself, e.g., interrupts worker threads in a pool.
- An ExecutorService instance can be in one of three states
- Running: After being created via a factory method.
- Shutting Down: After being shut down gracefully or abruptly.
- Terminated: After all, tasks have completed.
Implementation:
Example
Java
// Java program to demonstrate the working of
// ExecutorService
// Importing required libraries
import java.io.*;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
// Class 1
// helper class extending Runnable interface
class Service implements Runnable {
// member variable of this class
int i;
// Constructor of this class
public Service(int i)
{
// Initializing the counter variable
this.i = i;
}
// Method
// @Override
public void run()
{
// Printing the counter
System.out.println(i + " ");
// Try block to check for exceptions
try {
// Making thread to sleep for 1 second
// using the sleep() method
Thread.sleep(1000);
}
// Catch block to handle the exceptions
catch (InterruptedException e) {
// Print the line number and the corresponding
// exception occurred
e.printStackTrace();
}
}
}
// Class 2
// Main class
// ExecutorUtility
public class GFG {
// Main driver method
public static void main(String[] args)
{
// Creating an object of ExecutorService class to
// create fixed size thread pool
ExecutorService es
= Executors.newFixedThreadPool(5);
// Print the time difference before completion
System.out.println(new Date());
for (int i = 0; i < 25; i++) {
// Executes the given command at some time in
// the future
es.execute(new Service(i));
}
// Executor is shut down so that
// its task can be considered complete
es.shutdown();
// Print the time difference after completion
System.out.println(new Date());
}
}
Output:

Now finally let us conclude the differences between Fork/Join Framework and ExecutorService which ais as follows:
Fork/Join Framework | ExecutorService |
---|
The Fork/Join framework in Java 7 is an implementation of the Divide and Conquer algorithm, in which a central ForkJoinPool executes branching ForkJoinTasks. | ExecutorService is an Executor that provides methods to manage the progress-tracking and termination of asynchronous tasks. |
Fork/Join Framework makes use of Work Stealing Algorithm. In the Fork/Join framework, when a task is waiting for the completion of the sub-tasks it has created using the join operation, the worker thread that is executing that task looks for another task that has not been executed yet and steals them to start their execution. | Unlike Fork/Join Framework, when a task is waiting for the completion of the sub-tasks it has created using the join operation, the worker thread that is executing that waiting task doesn't look for another task. |
Fork-join is wonderful for recursive problems, where a task involves running subtasks and then processing their results. | If you try to solve a recursive problem like this using ExecutorService, you end up with threads tied up waiting for other threads to deliver results to them. |
Fork Join is an implementation of ExecuterService. The main difference is that this implementation creates a DEQUE worker pool. | Executor service creates asked number of thread, and apply a blocking queue to store all the remaining waiting task. |
Similar Reads
Difference between ExecutorService execute() and submit() method in Java The ExecutorService interface extends Executor by adding methods that help manage and control the execution of threads. It is defined in java.util.concurrent package. It defines methods that execute the threads that return results, a set of threads and that determine the shutdown status. In this art
4 min read
Difference between fork() and exec() Every application(program) comes into execution through means of process, process is a running instance of a program. Processes are created through different system calls, most popular are fork() and exec() fork() pid_t pid = fork(); fork() creates a new process by duplicating the calling process, T
4 min read
Difference between fork() and vfork() 1. fork() : Fork() is system call which is used to create new process. New process created by fork() system call is called child process and process that invoked fork() system call is called parent process. Code of child process is same as code of its parent process. Once child process is created, b
2 min read
Differences between wait() and join() methods in Java The wait() and join() methods are used to pause the current thread. The wait() is used in with notify() and notifyAll() methods, but join() is used in Java to wait until one thread finishes its execution. wait() is mainly used for shared resources, a thread notifies other waiting thread when a resou
2 min read
Difference between spawn() and fork() methods in Node.js Node.js provides several ways to create child processes, enabling you to run tasks in parallel and leverage multi-core systems efficiently. Two commonly used methods for this purpose are spawn() and fork(). While they might seem similar, they serve different purposes and have distinct features. This
4 min read
Difference between Multi-tasking and Multi-threading Multi-tasking is the ability of an operating system to run multiple processes or tasks concurrently, sharing the same processor and other resources. In multitasking, the operating system divides the CPU time between multiple tasks, allowing them to execute simultaneously. Each task is assigned a tim
6 min read
Difference between RMI and Socket In the client-server model, the major step is to create a connection to employ for communication between the two. Two proven methods among them applicable in Java and networking are Remote Method Invocation (RMI) and Sockets. Although both are employed to link a client to a server, they are differen
6 min read
Difference between Multiprocessing and Multiprogramming Multiprocessing and Multiprogramming both strategies are designed to increase the efficiency of the system by managing multiple tasks but with different principles of their own. But they share the common goal which is improving resource utilization and system throughput. So, understanding which one
5 min read
FixedSizeThreadPoolExecutor in Java Executor Framework In a fixed thread pool, the number of threads in the pool depends on the type of task. For CPUs-intensive tasks like encryption, implementing hash algorithms, the number of threads depends on the number of cores. Thus, every thread runs on its core and once it is done executing the task it picks up
5 min read
Difference between Multiprocessing and Multithreading Multiprocessing uses multiple CPUs to run many processes at a time while multithreading creates multiple threads within a single process to get faster and more efficient task execution. Both Multiprocessing and Multithreading are used to increase the computing power of a system in different ways. In
3 min read