1.先抄一段廖雪峰大牛对Fork/Join框架的介绍:
Java 7开始引入了一种新的Fork/Join线程池,它可以执行一种特殊的任务:把一个大任务拆成多个小任务并行执行。
我们举个例子:如果要计算一个超大数组的和,最简单的做法是用一个循环在一个线程内完成:
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
还有一种方法,可以把数组拆成两部分,分别计算,最后加起来就是最终结果,这样可以用两个线程并行执行:
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
如果拆成两部分还是很大,我们还可以继续拆,用4个线程并行执行:
┌─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┘
┌─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┘
┌─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┘
┌─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┘
这就是Fork/Join任务的原理:判断一个任务是否足够小,如果是,直接计算,否则,就分拆成几个小任务分别计算。这个过程可以反复“裂变”成一系列小任务。
总结步骤主要有两步:
第一、任务切分;
第二、结果合并
工作窃取(work-stealing)算法
2.使用fork/join框架编写一个求和的类
ComputerSumTask.java
package com.wying.demo.otherDemo2;
import java.util.concurrent.RecursiveTask;
/**
* description:计算总数任务 继承 RecursiveTask类 fork/join框架的核心类
* date: 2021/12/22
* author: gaom
* version: 1.0
*/
public class ComputerSumTask extends RecursiveTask<Integer> {
//设置任务切分的阈值
public static final int THREAD_HOLD=2;
private int start;
private int end;
public ComputerSumTask(int start,int end){
this.start=start;
this.end=end;
}
@Override
protected Integer compute() {
int sum=0;
//如果任务足够小就直接计算
boolean b = (end - start) <= THREAD_HOLD;
System.out.println("ThreadId:"+Thread.currentThread().getId()+" end:"+end+" start:"+start +" b:"+b);
if(b){
System.out.println("ThreadId:"+Thread.currentThread().getId()+" end:"+end+" start:"+start +" b:"+b+" 任务足够小直接计算 ");
for(int i=start;i<=end;i++){
sum+=i;
}
}else {
//切分任务
int middle = (start + end) / 2;
ComputerSumTask computerSumTask_left = new ComputerSumTask(start, middle);
ComputerSumTask computerSumTask_right = new ComputerSumTask(middle+1, end);
//执行子任务
computerSumTask_left.fork();
computerSumTask_right.fork();
//获取子任务结果
int sum_left = computerSumTask_left.join();
int sum_right = computerSumTask_right.join();
sum = sum_left + sum_right;
System.out.println("ThreadId:" + Thread.currentThread().getId() + " end:" + end + " start:" + start + " b:" + b + " 切分任务 sum_left:" + sum_left + " sum_right:" + sum_right + " sum:" + sum);
}
return sum;
}
}
3.执行查看效果
ForkJoinMain.java
package com.wying.demo.otherDemo2;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
/**
* description:
* Fork/join 框架 运行测试
* date: 2021/12/21
* author: gaom
* version: 1.0
*/
public class ForkJoinMain {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ForkJoinPool forkJoinPool = new ForkJoinPool();
ComputerSumTask computerSumTask=new ComputerSumTask(1,10);
Future<Integer> sum=forkJoinPool.submit(computerSumTask);
System.out.print(sum.get());
}
}