“This is the second day of my participation in the Gwen Challenge in November. See details: The Last Gwen Challenge in 2021”
ForkJoin is a framework for parallel execution of tasks by breaking a large task into smaller tasks and summarizing the results of each smaller task
Parallel: When a system has multiple cpus, one CPU executes a process while the other CPU executes another process. The two processes can run concurrently without preempting each other’s cpus
For example, if the whole process takes 10 minutes to increase 1 to 100 million, divide the large computing task into four smaller tasks. One small task takes two minutes to execute, and several tasks are executed at the same time. The whole process only takes two minutes to complete, making full use of CPU computing resources
But there is a phenomenon of task distribution, multiple threads competing with each other, so there is a job stealing algorithm
Job stealing algorithm
To reduce contention between threads, these subtasks are placed in separate queues, each with a separate thread to execute the tasks in the queue
There could be another situation where thread A has finished its own queue and another thread has not finished
In order to avoid conflicts, thread A processes the unfinished tasks of thread B from the end of the queue, while thread B takes the tasks from the head of the queue
demo
Example: Find 1+… And + 100
- Create a ForkJoin thread pool
- Give a sum of tasks
- Delegating tasks to thread pools (which decompose tasks and merge results)
- Get the result and print it
- Close the ForkJoin thread pool
One of the most important steps is the third step of breaking down the task
The complete code is as follows:
public class TestTask extends RecursiveTask<Long> { int start; // where to start int end; Int step = 10; Public TestTask(int start, int end) {this.start = start; this.end = end; } @Override protected Long compute() { //1. Define the result variable Long sum = 0L; If ((end-start) <= step) {for (int I = start; i <= end; i++) { sum += i; Int mid = (start + end) / 2; TestTask oneTask = new TestTask(start, mid); TestTask twoTask = new TestTask(mid + 1, end); // continue to split onetask.fork (); twoTask.fork(); Long one = onetask.join (); Long two = twoTask.join(); sum = one + two; } return sum; } public static void main(String[] args) throws ExecutionException, InterruptedException { //1. Create a ForkJoin thread pool ForkJoinPool = new ForkJoinPool(); RecursiveTask task = new TestTask(1, 100); Future<Long> Future = pool.submit(task); Long result = future.get(); System.out.println(result); //5. Close the ForkJoin thread pool pool.shutdown(); }}Copy the code
The results
Compared with the normal running time
The following is a common implementation
Running time comparison
Comparing the results
It turns out that ForkJoin takes longer, so there is no need to split tasks if they are small