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 librariesimport java.io.*;import java.util.concurrent.ForkJoinPool;import java.util.concurrent.RecursiveTask;// Class 1// helper classclass 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 classpublic 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 ");    }} | 
6 found 3 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 librariesimport 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 interfaceclass 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// ExecutorUtilitypublic 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. | 
