多线程之 ForkJoinool线程池(二十四)

"分而治之"的一个有效的处理大数据的方法,著名的MapReduce就是采用这种分而治之的思路,简单点生活如果要处理的1000个数据,但是我们不具备处理1000个数据的能量,可以处理10个数据,可以把这个1000个数据分阶段处理100次,每次处理10个,吧100次的处理结果进行合成,形成最后的1000个数据的处理结果

把一个大任务调用fork()方法分解为若干个小任务,把小任务的处理结果进行join()合并为大任务的结果

在这里插入图片描述
系统对ForkJoinPool线程池进行了优化,提交的任务数量与线程的数量不一定是一对一的关系,在多数情况下,一个物理线程实际上需要处理多个逻辑任务

在这里插入图片描述
ForkJoinPool线程池中最常用的方法是:

ForkJoinTask submit(ForkJoinTask task) 向线程池提交一个ForkJoinTask任务,ForkJoinTask任务支持fork()分解与join等待的任务,ForkJoinTask有两个重要的子类:RecursiveAction和RecursiveTask

RecursiveAction任务没有返回值,RecursiveTask任务可以带返回值

dome


package com.dome.threadpool;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/**
 * @author qb
 * @version 1.0
 * @Description
 * 演示 ForkJoinPool线程池的使用
 * @date 2021/3/12 16:49
 */
public class Test09 {
    //计算数列的和,需要返回结果,可以定义任务继承RecursiveTask
    private static class CountTask extends RecursiveTask<Long>{

        private static final int THRESHOLD = 10000; //数据规模的阈值,允许计算10000个数内的和,超过failed阈值的数列就分解

        //每次吧大任务分解为100个小任务
        private static final int TASKNUMBER = 100;

        private long start;  //计算数列的开始位置

        private long end; //结束位置

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

        @Override
        protected Long compute() {
            long sum = 0; //保存计算的结果
            //判断任务是否需要继续分解,如果当前数列end与start范围的超过阈值THRESHOLD,就继续分解
            if(end - start < THRESHOLD){
                //小于就直接计算
                for (long i = start; i <= end; i++) {
                    sum += i;
                }

            }else{
                //超过阈值,继续分解
                //约定每次分解为100个小任务,就计算每个任务的计算量
                long step = (start + end ) /TASKNUMBER;
                //start = 0; end=200000; step = 2000;
                //如果计算[0,200000] 把该范围内的数列费结为100个小任务,每个任务就计算2000个数即可
                //如果任务划分的层次很深THRESHOLD阈值太小,每个人的计算量很小,这个层次划分就会很深
                //1.系统内的线程数量会越积越多,导致系统性能下降
                //2.分解任务过多,层次过深,方法调用过多可能会导致栈溢出
                //创建一个存储任务的集合
                ArrayList<CountTask> subTaskList = new ArrayList<>();
                long pos = start;//每个任务的起始位置
                for (int i = 0; i < TASKNUMBER; i++) {

                    long lastOne = pos +step; //没个任务的结束任务
                    //调整最后一个任务的结束位置
                    if(lastOne > end){
                        lastOne = end;
                    }
                    CountTask countTask = new CountTask(pos,lastOne);
                    //把任务添加到集合中
                    subTaskList.add(countTask);
                    //调用fork()提交任务
                    countTask.fork();
                    //调整下个任务的起始位置
                    pos += step+1;
                }

                //等待所有子任务结束后合并结果
                for(CountTask task : subTaskList){
                    sum += task.join(); //join一直等待子任务执行完毕,
                }

            }


            return sum;
        }
    }

    public static void main(String[] args) {
        //创建ForkJoinPool线程池
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        //创建大的任务
        CountTask task = new CountTask(0,200000L);
        //把大任务提交线程池
       ForkJoinTask<Long> r = forkJoinPool.submit(task);
        try {
           Long res =  r.get();
            System.out.println("结果为:"+res);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        long s = 0L;

        for (int i = 0; i <= 200000; i++) {
            s += i;
        }
        System.out.println("s:"+s);
    }

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值