JUC并发编程(九)-- Fork/Join框架
一、什么是Fork/Join
1、概述
fork/join 框架可以将一个大任务,拆分成一个个的小任务,然后分别计算,将得到的结果相加后,给出一个完整的结果。
2、特点
fork/join还有一个特点,叫:工作窃取。
什么是工作窃取??
有这样一个场景,有两个线程A和B,都分配了四个任务,A线程刚刚执行了一个任务,而B线程已经执行完了分配给它的四个任务,那么这个时候,通常情况下,B线程就会无事可做,而A线程就会继续执行剩下的三个任务,而fork/join 框架下,则会让B线程去盗取A线程的任务,给A线程帮忙,做剩下的任务。
二、代码实现
首先自己定义一个任务类:
package com.zhan.juc.forkjoin;
import java.util.concurrent.RecursiveTask;
/**
* @Author Zhanzhan
* @Date 2020/12/21 20:30
*/
public class ForkJoinDemo extends RecursiveTask<Integer> {
private static final long serialVersionUID = 1L;
private static final long THRESHOLD = 1000; // 临界值,达到此值就拆分任务
private int start; // 子任务开始的边界
private int end; // 子任务结束的边界
public ForkJoinDemo(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
if ((end - start) <= THRESHOLD) { // 进行计算
int sum = 0;
for (int i = start; i <= end; i++) {
sum += i;
}
return sum;
} else { // 拆分任务
int mid = (start + end) / 2; // 将边界值一分为二,其实和归并排序的思想类似,也是种递归
ForkJoinDemo task1 = new ForkJoinDemo(start, mid);
ForkJoinDemo task2 = new ForkJoinDemo(mid + 1, end);
invokeAll(task1, task2);
return task1.join() + task2.join();
}
}
}
然后还有测试类:
package com.zhan.juc.forkjoin;
import java.util.OptionalInt;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.IntStream;
/**
* @Author Zhanzhan
* @Date 2020/12/21 20:54
*/
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
test1();
test2();
test3();
}
/**
* 用for循环 来计算
*/
public static void test1() {
int sum = 0;
long start = System.currentTimeMillis();
for (int i = 0; i <= 1000000000; i++) {
sum += i;
}
long end = System.currentTimeMillis();
System.out.println("sum=" + sum + ",耗费的时间为:" + (end - start) + "毫秒");
}
/**
* 使用 fork/join 来计算
*/
public static void test2() throws ExecutionException, InterruptedException {
long start = System.currentTimeMillis();
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Integer> submit = forkJoinPool.submit(new ForkJoinDemo(0, 1000000000));
long sum = submit.get();
long end = System.currentTimeMillis();
System.out.println("sum=" + sum + ",耗费的时间为:" + (end - start) + "毫秒");
}
/**
* 使用 stream 并行流
*/
public static void test3() {
long start = System.currentTimeMillis();
OptionalInt result = IntStream
.rangeClosed(0, 1000000000)
.parallel()
.reduce(Integer::sum);
long end = System.currentTimeMillis();
System.out.println("sum=" + result.getAsInt() + ",耗费的时间为:" + (end - start) + "毫秒");
}
}
结果如下: