What is the forkjoin framework in the concurrent programming series?
1. What is the forkjoin framework
The forkjoin framework is provided in the JUC package of Java. It is used to handle some heavy tasks. It will divide the big task into multiple small tasks. After the completion of multiple small tasks, the results will be summarized to the result, reflecting the idea of “divide and rule”. The first step is to split the fork task into several small tasks; The second step, merge join, will merge the processing results of small tasks into one result.

2、ForkJoinTask
ForkJoinTask
yesForkJoin
The task API provided by the framework,ForkJoinTask
Is an abstract class with two main implementation classes,RecursiveTask
andRecursiveAction
WhereRecursiveTask
andRecursiveAction
The main difference is that,RecursiveAction
No return value, andRecursiveTask
It has a return value

3、ForkJoinPool
The forkjoinpool class is the thread pool implementation of the forkjoin framework, based on the executorservice interface. This thread pool was added only in jdk1.7 to manage threads and execute forkjoin tasks. For the use of thread pool, we often use ThreadPoolExecutor. You can see from the UML class diagram in the idea that forkjoinpool and ThreadPoolExecutor are similar in implementation.

ForkJoinPool()
ForkJoinPool(int parallelism)
ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler, boolean asyncMode)
Several important parameters:
- Parallelism: parallelism. Parallel execution threads can be specified or not specified. If not specified, available threads are created according to the number of CPU cores
- Forkjoinworkerthreadfactory: factory implementation for creating threads
- Uncaughtexceptionhandler: callback handling interrupted because of unknown exception
- Asyncmode: whether it is asynchronous. The default is false
When in use, you can directly create a forkjoinpool without parameters. By default, the specified thread parallelism isRuntime.getRunTime().availableProcessors();
, indicating the number of available threads created according to the number of CPU cores
ForkJoinPool forkJoinPool = new ForkJoinPool();
ArraySortTask task = new ArraySortTask(array , 0 , size);
forkJoinPool.submit(task);
task.get();
You can also specify the parallelism by passing parameterspublic ForkJoinPool(int parallelism)
, parallelism, parallel execution of several threads
There are several ways to add a forkjoin task to the frokjoinpool thread pool
- Execute (): call its fork method to split work among multiple threads.
- Invoke (): invoke the invoke method on the forkjoinpool thread pool
- Submit(): returns a future object, which can be monitored by future, and returns the result after the task is completed
4. Print Fibonacci series
The forkjoin framework can be used in some recursive traversal scenarios. You can be familiar with Fibonacci sequence, because it is often asked in the interview that the result of the last item is equal to the sum of the first two items
package com.example.concurrent.forkjoin;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
/**
* <pre>
*Fibonacci sequence
* </pre>
* <p>
* <pre>
* @author nicky.ma
*Modification record
*Modified version: modified by: modified date: October 12, 2021 16:22 modified content:
* </pre>
*/
public class Fibonacci extends RecursiveTask<Integer>{
private int n;
public Fibonacci(int n) {
this.n = n;
}
@Override
protected Integer compute() {
if (n <= 1)
return n;
Fibonacci f1 = new Fibonacci(n - 1);
f1.fork();
Fibonacci f2 = new Fibonacci(n - 2);
f2.fork();
return f1.join() + f2.join();
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ForkJoinPool pool = new ForkJoinPool();
for (int i = 0; i< 10; i++) {
ForkJoinTask task = pool.submit(new Fibonacci(i));
System.out.println(task.get());
}
}
}
5. Forkjoin merge sort
Interview question: quickly sort an array with a length of millions
Difficulty: merge sort can be used. How can multithreads organize and implement merge sort
package com.example.concurrent.forkjoin;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
/**
* <pre>
*Large array sort
* </pre>
* <p>
* <pre>
* @author mazq
*Modification record
*Modified version: modified by: modified date: October 12, 2021 17:04 modified content:
* </pre>
*/
public class ArraySortTask extends RecursiveAction{
final long[] array; final int lo, hi;
ArraySortTask(long[] array, int lo, int hi) {
this.array = array; this.lo = lo; this.hi = hi;
}
ArraySortTask(long[] array) { this(array, 0, array.length); }
@Override
protected void compute() {
if (hi - lo < THRESHOLD)
//Less than the threshold, use arrays Sort quick platoon
sortSequentially(lo, hi);
else {
/*Merge sort*/
//Take intermediate value
int mid = (lo + hi) >>> 1;
//Split task
invokeAll(new ArraySortTask(array, lo, mid),
new ArraySortTask(array, mid, hi));
//Merging result
merge(lo, mid, hi);
}
}
// implementation details follow:
static final int THRESHOLD = 1000;
void sortSequentially(int lo, int hi) {
Arrays.sort(array, lo, hi);
}
void merge(int lo, int mid, int hi) {
long[] buf = Arrays.copyOfRange(array, lo, mid);
for (int i = 0, j = lo, k = mid; i < buf.length; j++)
array[j] = (k == hi || buf[i] < array[k]) ?
buf[i++] : array[k++];
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
int size = 10_000;
long[] array = new long[size];
Random random = new Random();
for (int i = 0; i< size; i++) {
array[i] = random.nextInt();
}
ForkJoinPool forkJoinPool = new ForkJoinPool();
ArraySortTask task = new ArraySortTask(array , 0 , size);
forkJoinPool.submit(task);
task.get();
for (long a : array) {
System.out.println(a);
}
}
}