1. JDK中ForkJoin实现概述
在JavaSE7的API和JDK1.7中,分别集成了支持ForkJoin的五个类:
- ForkJoinPool 实现ForkJoin的线程池
- ForkJoinWorkerThread 实现ForkJoin的线程
- ForkJoinTask 一个描述ForkJoin的抽象类
- RecursiveAction 无返回结果的ForkJoinTask实现
- RecursiveTask 有返回结果的ForkJoinTask实现
ForkJoin样例解析
public class ForkJoinAction {
public static void main(String[] args) {
//创建一个包含20个并行线程的ForkJoinPool
ForkJoinPool pool = new ForkJoinPool(20);
//创建一个包含三个子任务的forkjointask
List<ChildTask> childTaskList = new ArrayList<ChildTask>();
childTaskList.add(new ChildTask());
childTaskList.add(new ChildTask());
childTaskList.add(new ChildTask());
ParentTask task = new ParentTask(childTaskList, 0, childTaskList.size());
/*把任务放入到 1、当前线程队列(当当前线程为ForkJoinWorkerThread时)或者 2、线程池队列中
* 1、会被当前线程执行或者被别的ForkJoinWorkerThread窃取执行
* 2、线程池队列中的任务最后被执行,执行顺序1、线程任务队列中的task,2、窃取别的线程的task,3、执行线程池中的task。
* */
pool.execute(task);
while(!task.isDone()&&(!task.isCancelled())){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int result = task.getRawResult();
System.out.println(result);
}
}
public class ParentTask extends RecursiveTask<Integer>{
private int TaskGgranularity;//最小任务粒度
List<ChildTask> childTaskList;
private int start;
private int end;
public ParentTask(List<ChildTask> childTaskList, int start, int end){
this.childTaskList = childTaskList;
this.start = start;
this.end = end;
}
/**
* ForkJoinWorkerThread执行执行task的入口,并且返回值会被赋值给result,由getRawResult()取出
*/
@Override
protected Integer compute() {
if(childTaskList==null||childTaskList.size()==0) return 0;
if(end-start<=TaskGgranularity){//如果子任务粒度已经达到最小任务粒度,即任务不需再拆分。当前ForkJoinWorkerThread自己自行
ChildTask task = childTaskList.get(start);
return task.compute();
}else{//如果子任务粒度没有达到最小任务粒度,则把任务从中间一分为二
int middle = (start + end) /2;
ParentTask task1 = new ParentTask(childTaskList, start, middle);
ParentTask task2 = new ParentTask(childTaskList, middle, end);
/*当前ForkJoinWorkerThread执行task1,并把task2放入到线程任务队列当中,通常task2会被别的任务线程窃取执行(并发,fork的体现)
* 并且只有当两个task都已经被执行完成时,才会继续往后面走(join的体现)
*/
invokeAll(task1, task2);
//返回task1+task2的执行结果(compute()的返回值)
return task1.getRawResult()+task2.getRawResult();
}
}
}
public class ChildTask extends RecursiveTask<Integer>{
@Override
protected Integer compute() {
return calc();
}
private int calc() {
return 10;
}
}
public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) {
t2.fork();//放入到线程task队列中,被别的线程窃取执行
t1.invoke();//当前线程执行
t2.join();//等待被窃取的线程执行完t2任务后,合并
}
以上代码部分已经注释的很明白,详细原理可以自己去看源代码。