Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”
This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.
1. Introduction to Fork/Jion framework
Brief introduction to Fork/Join: It is to Fork a large task into several small tasks if necessary, and then Join the results of each small task. ForkJoin is a multi-line concurrent processing framework developed in JDK1.7. The basic idea behind ForkJoin is to divide and conquer.
Fork/Jion features: Job stealing
Note: The task queue is a dual-end queue, which can work in first-in, first-out mode or last-in, first-out mode.
2. Use of Fork/Jion
To use the ForkJoin framework or ForkJoinPool, create a ForkJoin task. ForkJoinPool provides two implementation classes for RecursiveAction and RecursiveTask.
The difference between the two implementation classes is that a RecursiveAction task does not return a value, and a RecursiveTask can have a return value.
ForkJoin example: A large amount of data is added
package com.cheng.forkjoin;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;
public class ForkJoinDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//1
long start1 = System.currentTimeMillis();
Long sum1 = 0L;
for (Long i = 1L; i <= 10 _0000_0000; i++) {
sum1 += i;
}
long end1 = System.currentTimeMillis();
System.out.println("Sum1 ="+sum1+", time ->"+(end1-start1));Sum1 =500000000500000000, time -> 7896
//2. Use ForkJoin to calculate
long start = System.currentTimeMillis();
ForkJoinPool forkJoinPool = new ForkJoinPool();
SumTask task = new SumTask(1L.10_0000_0000L);
ForkJoinTask<Long> submit = forkJoinPool.submit(task);// Submit a ForkJoinTask to the ForkJoinPool
Long sum = submit.get();// Get the execution result
long end = System.currentTimeMillis();
System.out.println("ForkJoin sum="+sum+", time ->"+(end-start));Sum =500000000500000081, time -> 168
//3. Use Stream for parallel computation
long start2 = System.currentTimeMillis();
long sum2 = LongStream.rangeClosed(0.10 _0000_0000)// Generate a number between 0 and 10_0000_0000
.parallel()// Switch to a parallel stream, where a content is divided into internal blocks and each block is processed separately by a different thread
.reduce(1, Long::sum);
long end2 = System.currentTimeMillis();
System.out.println(Sum ="+sum2+", time ->"+(end2-start2));//sum=500000000500000000, time -> 7406}}// Compute task class, inheriting RecursiveTask with return value
class SumTask extends RecursiveTask<Long> {
private Long start; // The value that the subtask began to calculate
private Long end; // The value calculated at the end of the subtask
static final Long TEMP = 10000L;// Tasks that exceed this threshold need to be decomposed
public SumTask(Long start, Long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute(a) {
// If this condition is true, the number of values required for the task is small enough to start the formal summation
Long sum = 0L;
if ((end - start) < TEMP){
for (Long i = start; i <= end; i++) {
sum += i;
}
return sum;
// If not, split the task into two tasks
}else {
Long middle = (start + end) / 2;
SumTask task1 = new SumTask(start, middle);
task1.fork();// Put the newly created subtask into the work queue of the current thread
SumTask task2 = new SumTask(middle +1, end);
task2.fork();
return task1.join() + task2.join();// Join () waits for the subtask to complete and returns the result}}}Copy the code