ForkJoinPool
ForkJoin算法执行大概流程
任务的拆分 fork,直到判断任务已经足够细粒度(原子任务),底层用到递归 类似微服务项目
此时开始执行任务 当前被分解的任务不需要返回值那么任务完成则执行结束,当需要返回值时就会有下面的join操作:
每个细粒度join完会和同层被fork的任务进行join得到返回的结果
由此我们可以看出对于ForkJoinPool来说一个大任务会细分多个子任务,每个子任务可以继续划分多个子任务直到不能划分为主,当各个阶段的任务都执行完此时会合并各个阶段返回的数据组成最终的返回值 相比于ThreadPoolExecutor来说 同一个任务ForkJoinPool可以被多个线程执行而ThreadPoolExecutor只能被一个线程执行.
工作窃取
每个线程执行的任务存在一个队列当中,当某一线程执行完自己的任务就会去窃取其他线程的任务,由于双向队列的原因每个线程的任务队列都是互通的在这里插入代码片
ForkJoinTask
当我们使用callable或者是runnable 时任务窃取不会生效 此时只有实现ForkJoinTask类的子任务才会生效
RecursiverAction执行的任务没有返回值RecursiverTask执行的任务有返回值
示例
10-100的计算
public class MyTest4 {
public static void main(String[] args) {
//不显示线程数量 默认是CPU核心数*2
ForkJoinPool forkJoinPool = new ForkJoinPool();
MyTask myTask = new MyTask(1,100 );
Integer invoke = forkJoinPool.invoke(myTask);
System.out.println(invoke);
forkJoinPool.shutdown();
}
}
class MyTask extends RecursiveTask<Integer> {
//两数之间间隔数
private int limit = 4;
//首
private int firstIndex;
//尾
private int lastIndex;
public MyTask(int firstIndex, int lastIndex) {
this.firstIndex = firstIndex;
this.lastIndex = lastIndex;
}
@Override
protected Integer compute() {
int result = 0;
int gap = lastIndex - firstIndex;
boolean flag = gap <= limit;
if (flag) {
System.out.println(Thread.currentThread().getName());
for (int i = firstIndex; i <= lastIndex; i++) {
result += i;
}
} else {
//不符合要求对任务进行拆分
int middleIndex = (firstIndex + lastIndex) / 2;
MyTask leftTask = new MyTask(firstIndex, middleIndex);
MyTask rightTask = new MyTask(middleIndex + 1, lastIndex);
//执行递归操作 ForkJoinTask的静态方法 内部会执行我们重写的compute
// invokeAll(leftTask, rightTask);
// //同上
// invokeAll(leftTask);
// invokeAll(rightTask);
//同上
ArrayList<MyTask> objects = new ArrayList<>();
objects.add(rightTask);
objects.add(leftTask);
invokeAll(objects);
/*
join() 获取任务执行汇总结果
*/
int leftTaskResult = leftTask.join();
int rightTaskResult = rightTask.join();
result = leftTaskResult + rightTaskResult;
}
return result;
}
}
参看
fork/invokAll的区别
参看