Fork/Join框架

Fork/Join框架的思想

Fork/Join的思想是一个分而治之的思想的实现,跟MapReduce的思想如出一辙,简单的说就是加入我们需要处理1000个数据,但是我们并不具备处理1000个数据的能力,那么我们可以让一个线程只处理其中的10个,然后分阶段处理100次,将100次的结果进行合并,那么就会得到对最终的1000个数据的处理结果

JDK并发包中的实现

在实际应用中,我们没有办法毫无顾忌地使用fork()开启线程进行处理,假使我们这么做了,那么很有可能导致系统开启过多的线程而严重影响性能。所以在JDK中,给出了一个ForkJoinPool的线程池,对于fork()方法并不急着开启线程,而是提交给ForkJoinPool线程池进行处理,以节省系统资源。
ForkJoinPool的submit方法:

public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task)

这个方法需要一个ForkJoinTask类型的参数,ForkJoinTask就是支持fork()分解和join()等待的任务。ForkJoinTask是一个抽象类,它有两个子类,他们分别表示没有返回值的任务和有返回值的任务

RecursiveAction
RecursiveTask<V>

图解Fork/Join框架:
图解Fork/Join框架

案例

计算若干个数值的和

public class CountTask extends RecursiveTask<Long>{

    //每次相加的范围是1000个数
    private static final Long THRESHOLD = 10L;
    private long start;
    private long end;

    public CountTask(long start, long end) {
        super();
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        long sum = 0;
        boolean canCompute = (end-start)<THRESHOLD;
        if(canCompute){
            System.out.println(start+"\t"+end);
            for(long i =start;i<=end;i++){
                sum+=i;
            }
        }else{
            //分成若干个小任务
            long step = (end-start+1)/10;
            List<CountTask> subTasks = new ArrayList<>();
            for(int i=0;i<Math.ceil((end-start+1)/10.0);i++){
                CountTask countTask = null;
                if((start+step*(i+1)-1)>end){
                    countTask = new CountTask(start+step*i, end);
                }else{
                    countTask = new CountTask(start+step*i, start+step*(i+1)-1);
                }
                subTasks.add(countTask);
                countTask.fork();
            }
            for(CountTask c:subTasks){
                sum+=c.join();
            }
        }
        return sum;
    }

    public static void main(String[] args) throws Exception {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        CountTask countTask = new CountTask(1, 101);
        ForkJoinTask<Long> forkJoinTask = forkJoinPool.submit(countTask);
        System.out.println(forkJoinTask.get());
    }
}

新建一个可以fork()/join()的任务,由于是计算总和,所以这里我们需要有返回值的任务,这里就是继承RecursiveTask
重写compute方法,在这个里面对任务进行分解
针对每一个分解的任务,进行fork操作
针对每一个被分解的任务进行join操作,等待任务执行完毕后的数据的汇总
注意
由于我们这里边使用的是递归的方式,所以我们需要注意不能将任务划分的过深,否则会造成下面的问题:
* 系统内的线程越积越多,导致性能的严重下降
* 函数的调用层次(递归的层次)过多,导致栈溢出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值