"分而治之"的一个有效的处理大数据的方法,著名的MapReduce就是采用这种分而治之的思路,简单点生活如果要处理的1000个数据,但是我们不具备处理1000个数据的能量,可以处理10个数据,可以把这个1000个数据分阶段处理100次,每次处理10个,吧100次的处理结果进行合成,形成最后的1000个数据的处理结果
把一个大任务调用fork()方法分解为若干个小任务,把小任务的处理结果进行join()合并为大任务的结果
系统对ForkJoinPool线程池进行了优化,提交的任务数量与线程的数量不一定是一对一的关系,在多数情况下,一个物理线程实际上需要处理多个逻辑任务
ForkJoinPool线程池中最常用的方法是:
ForkJoinTask submit(ForkJoinTask task) 向线程池提交一个ForkJoinTask任务,ForkJoinTask任务支持fork()分解与join等待的任务,ForkJoinTask有两个重要的子类:RecursiveAction和RecursiveTask
RecursiveAction任务没有返回值,RecursiveTask任务可以带返回值
dome
package com.dome.threadpool;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
/**
* @author qb
* @version 1.0
* @Description
* 演示 ForkJoinPool线程池的使用
* @date 2021/3/12 16:49
*/
public class Test09 {
//计算数列的和,需要返回结果,可以定义任务继承RecursiveTask
private static class CountTask extends RecursiveTask<Long>{
private static final int THRESHOLD = 10000; //数据规模的阈值,允许计算10000个数内的和,超过failed阈值的数列就分解
//每次吧大任务分解为100个小任务
private static final int TASKNUMBER = 100;
private long start; //计算数列的开始位置
private long end; //结束位置
public CountTask(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long sum = 0; //保存计算的结果
//判断任务是否需要继续分解,如果当前数列end与start范围的超过阈值THRESHOLD,就继续分解
if(end - start < THRESHOLD){
//小于就直接计算
for (long i = start; i <= end; i++) {
sum += i;
}
}else{
//超过阈值,继续分解
//约定每次分解为100个小任务,就计算每个任务的计算量
long step = (start + end ) /TASKNUMBER;
//start = 0; end=200000; step = 2000;
//如果计算[0,200000] 把该范围内的数列费结为100个小任务,每个任务就计算2000个数即可
//如果任务划分的层次很深THRESHOLD阈值太小,每个人的计算量很小,这个层次划分就会很深
//1.系统内的线程数量会越积越多,导致系统性能下降
//2.分解任务过多,层次过深,方法调用过多可能会导致栈溢出
//创建一个存储任务的集合
ArrayList<CountTask> subTaskList = new ArrayList<>();
long pos = start;//每个任务的起始位置
for (int i = 0; i < TASKNUMBER; i++) {
long lastOne = pos +step; //没个任务的结束任务
//调整最后一个任务的结束位置
if(lastOne > end){
lastOne = end;
}
CountTask countTask = new CountTask(pos,lastOne);
//把任务添加到集合中
subTaskList.add(countTask);
//调用fork()提交任务
countTask.fork();
//调整下个任务的起始位置
pos += step+1;
}
//等待所有子任务结束后合并结果
for(CountTask task : subTaskList){
sum += task.join(); //join一直等待子任务执行完毕,
}
}
return sum;
}
}
public static void main(String[] args) {
//创建ForkJoinPool线程池
ForkJoinPool forkJoinPool = new ForkJoinPool();
//创建大的任务
CountTask task = new CountTask(0,200000L);
//把大任务提交线程池
ForkJoinTask<Long> r = forkJoinPool.submit(task);
try {
Long res = r.get();
System.out.println("结果为:"+res);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
long s = 0L;
for (int i = 0; i <= 200000; i++) {
s += i;
}
System.out.println("s:"+s);
}
}