For&Join 框架

For&Join框架又称分支合并框架,把一个大的任务Fork分解为若干个小任务多线程处理,返回结果Jion汇总返回。采用了分治策略和递归算法。

工作窃取模式:

     


框架包 java.util.concurrent

第一步分割任务。首先我们需要有一个fork类来把大任务分割成子任务,有可能子任务还是很大,所以还需要不停的分割,直到分割出的子任务足够小。注:分治策略和递归算法

第二步执行任务并合并结果。分割的子任务分别放在双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务执行完的结果都统一放在一个队列里,启动一个线程从队列里拿数据,然后合并这些数据。

Fork/Join使用两个类来完成以上两件事情:

  • ForkJoinTask:我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行fork()和join()操作的机制,通常情况下我们不需要直接继承 ForkJoinTask类,而只需要继承它的子类,Fork/Join框架提供了以下两个子类:
    • RecursiveAction:用于没有返回结果的任务。
    • RecursiveTask :用于有返回结果的任务。
  • ForkJoinPool :ForkJoinTask需要通过ForkJoinPool来执行,任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务。


框架的使用:

     计算:1+2+3+4;

  

package cn.yh.jdk_8.forkjoin
import java.util.concurrent.RecursiveTask;

/**
 * Created by liang on 2017/3/3.
 */
public class ForkJoinTaskCaculator extends RecursiveTask{

    private int start;
    private int end;
    private final int THRODHOLD = 2;

    public ForkJoinTaskCaculator(int start, int end){
        this.start = start;
        this.end = end;
    }
    @Override
    protected Integer compute() {
        int sum = 0;
        if(end-start<=THRODHOLD){ //任务分割足够小
            sum = caculator(start,end);
        }else {
            ForkJoinTaskCaculator leftTask = new ForkJoinTaskCaculator(start,start+(end-start)/2);
            ForkJoinTaskCaculator rightTask = new ForkJoinTaskCaculator(start+(end-start)/2,end);
            leftTask.fork();//回调该函数
            rightTask.fork();
            //等待计算完毕 和并字任务
            int leftResult = leftTask.join();
            int rightResult = rightTask.join();
            sum = leftResult + rightResult;
        }
        return sum;
    }
    private int caculator(int start,int end){
        int result = 0;
        for (int i=start;i;i++){
            result +=i;
        }
        return result;
    }
}


框架实现原理:

    

ForkJoinPool由ForkJoinTask数组和ForkJoinWorkerThread数组组成,ForkJoinTask数组负责存放程序提交给ForkJoinPool的任务,而ForkJoinWorkerThread数组负责执行这些任务。

ForkJoinTask的fork方法实现原理。当我们调用ForkJoinTask的fork方法时,程序会调用ForkJoinWorkerThread的pushTask方法异步的执行这个任务,然后立即返回结果。代码如下:

public final ForkJoinTask fork() {

        ((ForkJoinWorkerThread) Thread.currentThread())

             pushTask(this);

        return this;

}

pushTask方法把当前任务存放在ForkJoinTask 数组queue里。然后再调用ForkJoinPool的signalWork()方法唤醒或创建一个工作线程来执行任务。

ForkJoinTask的join方法实现原理。Join方法的主要作用是阻塞当前线程并等待获取结果。


参考:http://ifeve.com/customizing-concurrency-classes-1/





你可能感兴趣的:(For&Join 框架)