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完整图:
Java并发编程从入门到精通 之 第七章 JDK7新增的Fork/Join
-2 ForkJoinPool三个方法:
execute 异步执行指定任务
invoke和invokeAll执行指定的任务,等待完成,返回结果。
submit异步执行指定任务,并返回Future对象。

 
Fork/Join框架的实现原理:
-1 说明:这是一个特殊的线程池框架,分解汇总子任务。比起传统线程池ThreadPoolExecutor,而ForkJoinPool实现窃取算法。
-2 工作窃取算法:指某个线程从其他队列里窃取任务来执行。


Fork/Join模式优缺点及其实现应用场景:
-1 优点:不需要处理并行相关,例如同步,通信死锁等,仅需关注如何划分任务和组合中间结果。
-2 缺点:应避免拆分过多,造成内存撑满。
-3 应用场景:适合树形遍历和分析,如文件遍历