Java并发编程从入门到精通 之 第七章 JDK7新增的Fork/Join
认识Future任务机制和FutureTask:
-1 FutureTask:
public class FutureTask<V> implements RunnableFuture<V>
其中RunnableFuture实现了runnable和Future接口,所以可被线程执行,可得到Callable返回值。
-2 应用场景:
实际工作中,一个报表可分为多个模块给多个线程运算,然后再合并。而Fork/join是基于Ffuture实现
什么是Fork/Join框架:
-1 说明:Fork/Join是Java7提供的一个用于并行执行任务的框架,把大任务分割成小任务,最后汇总每个小任务结果到大任务。
-2 使用实例:
package forkJoin;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RecursiveTask;
public class Demo01 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ForkJoinPool forkJoinPool = new ForkJoinPool();
CountTask task = new CountTask(1, 5);
Future<Integer> result = forkJoinPool.submit(task);
System.out.println("1-5最终相加的结果:"+ result.get());
CountTask task2 = new CountTask(1, 100);
Future<Integer> result2 = forkJoinPool.submit(task2);
System.out.println("1-100最终相加结果:" + result2.get());
System.out.print("Thread main end");
}
}
class CountTask extends RecursiveTask<Integer> {
private static final long serialVersionUID = 3336021432713606929L;
private static int splitSize = 2;
private int start ,end;
public CountTask(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
int sum = 0;
//如果任务已经不需要再拆分了就开始计算
boolean canCompute = (end - start) <= splitSize;
if(canCompute) {
for(int i = start; i <= end; i++) {
sum = sum + i;
}
}else {
//拆分成两个子任务
int middle = (start + end)/2;
CountTask firstTask = new CountTask(start, middle);
CountTask secondTask = new CountTask(middle + 1, end);
firstTask.fork();//开始执行
secondTask.fork();//
//获得第一个子任务结果,得不到结果,此线程不会往下执行
int firstResult = firstTask.join();
int secondResult = secondTask.join();
//合并两个儿子的执行结果
sum = firstResult + secondResult;
}
return sum;
}
}
实现compute,判断任务是否足够小,如果足够小就执行任务,反之分割成两个任务,然后子任务调用fork,又会进入compute,继续分割子任务。然后使用join等待子任务执行完就会返回结果.
认识Fork/Join的JDK里面的家族:
-1 Fork/Join完整图:
-2 ForkJoinPool三个方法:
execute 异步执行指定任务
invoke和invokeAll执行指定的任务,等待完成,返回结果。
submit异步执行指定任务,并返回Future对象。
Fork/Join框架的实现原理:
-1 说明:这是一个特殊的线程池框架,分解汇总子任务。比起传统线程池ThreadPoolExecutor,而ForkJoinPool实现窃取算法。
-2 工作窃取算法:指某个线程从其他队列里窃取任务来执行。
Fork/Join模式优缺点及其实现应用场景:
-1 优点:不需要处理并行相关,例如同步,通信死锁等,仅需关注如何划分任务和组合中间结果。
-2 缺点:应避免拆分过多,造成内存撑满。
-3 应用场景:适合树形遍历和分析,如文件遍历