在JAVA7之前,并行处理数据非常麻烦。第一,你得明确把包含数据的数据结构分成若干份。第二,你要将每个子部分分配给一个独立的线程。第三,你要在恰当的时候对它们进行同步避免不希望的竞争条件,等待所有线程完成,最后把这些部分结果合并起来。在Java 7引入了分支/合并框架,让这些操作更稳定、更不容易出错。
分支/合并框架的目的是以递归的方式将可以并行的任务拆分为更小的任务,然后将每个子任务的结果合并起来生成整体结果。要把子任务提交到ForkJoinPool必须创建RecursiveTask
if 问题size < 阀值
直接解决问题;
else
切分生成多个子问题;
递归解决每个子问题;
合并结果;
ForkJoin框架的api支持:
ForkJoinPool:管理forjoin 框架里线程的执行
ForkJoinTask:一个抽象的类定义了task在ForkJoinPool里面的运行
RecursiveAction: ForkJoinTask的子类运行一个没有返回值的任务
RecursiveTask: ForkJoinTask的子类运行一个有返回值的任务
ForkJoinTask类代表了抽象的切成的任务,而不是实际的执行的线程, 这种机制允许一小部分数量的线程去管理执行一大部分任务。
ForkJoinTask还有一个compute方法,这个方法用来编写主要的计算逻辑:
ForkJoinPool类主要有两个提交任务的方法:
第一个是invoke会同步等待直到所有的任务返回并得到执行结果。
第二个是异步的提交使用execute方法,对于结果的获取需要调用任务的get方法来阻塞获取。或者使用get超时方法来轮询获取结果。
最后值得一提的是,对于ForkJoinPool方法,我们不需要显式的调用shutdown来关闭,其使用的是守护线程,只要所有的线程运行完毕,线程池会自动退出。
例如100个随机数求和:
import java.util.concurrent.RecursiveTask;
public class ThreadPoolExecutor extends RecursiveTask {
private int arr[];
private final int start;
private final int end;
// 每个“小任务”只最多只累加20个数
private static final int THRESHOLD = 10;
// 累加从start到end的数组元素
public ThreadPoolExecutor(int[] arr, int start, int end) {
super();
this.arr = arr;
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
int sum = 0 ;
if (end-start
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinTask;
public class ForkJoinPool {
public static void main(String[] args) throws ExecutionException, InterruptedException {
int quantity = 5;
int[] arr = new int[100];
Random rand = new Random();
int total = 0;
// 初始化100个数字元素
for (int i = 0 , len = arr.length; i < len ; i++ )
{
int tmp = rand.nextInt(20);
// 对数组元素赋值,并将数组元素的值添加到total总和中。
total += (arr[i] = tmp);
}
System.out.println(total);
java.util.concurrent.ForkJoinPool forkJoinPool = new java.util.concurrent.ForkJoinPool(quantity);
ThreadPoolExecutor countTask = new ThreadPoolExecutor(arr, 0 , arr.length);
// 提交可分解的CalTask任务
ForkJoinTask result = forkJoinPool.submit(countTask);
//线程阻塞,等待所有任务完成
//forkJoinPool.awaitTermination(10, TimeUnit.SECONDS);
System.out.println(result.get());
forkJoinPool.shutdown();
}
}
运行结果如下
初始化数据值:952
运算结果值:952