ForkJionPool线程池

分而治之
        简单点说, 如果要处理的 1000 个数据 , 但是我们不具备处理1000 个数据的能力 , 可以只处理 10
个数据, 可以把这 1000 个数据分阶段处理 100 , 每次处理 10 , 100 次的处理结果进行合成,
形成最后这 1000 个数据的处理结果 . 把一个大任务调用 fork() 方法分解为若干小的任务 , 把小任务
的处理结果进行 join()合并为大任务的结果
ForkJoinPool 线程池中最常用 的方法是 :
<T> ForkJoinTask<T> submit(ForkJoinTask<T> task) 向线程池提交 一个 ForkJoinTask 任务 .
ForkJoinTask 任务支持 fork() 分解与 join() 等待的 任 务 .
ForkJoinTask 有 两 个 重 要 的 子 类 :
       
 RecursiveAction 和 RecursiveTask ,
        
它们的区别在于 RecursiveAction 任务没有返回值 , RecursiveTask 任务可以带有返回值
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
public class Tets {
    //计算数列的和, 需要返回结果,可以定义任务继承 RecursiveTask
    private static class CountTask extends RecursiveTask<Long> {
        private static final int THRESHOLD = 10000; //定义数据规模的阈值,允许计算10000 个数内的和,超过该阈值的数列就需要分解
        private static final int TASKNUM = 100; //定义每次把大任务分解为 100 个小任务
        private long start; //计算数列的起始值
        private long end; //计算数列的结束值
        public CountTask(long start, long end) {
            this.start = start;
            this.end = end;
        }

        //重写 RecursiveTask 类的 compute()方法,计算数列的结果
        @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 ) / TASKNUM;
//start = 0 , end = 200000, step = 2000, 如果计算[0,200000]范围内数列的
 // 和, 把该范围的数列分解为 100 个小任务,每个任务计算 2000 个数即可
//注意,如果任务划分的层次很深,即 THRESHOLD 阈值太小,每个任务的计
 //               算量很小,层次划分就会很深,可能出现两种情况:一是系统内的线程数量会越积越多,导致性
 //               能下降严重; 二是分解次数过多,方法调用过多可能会导致栈溢出
//创建一个存储任务的集合
                ArrayList<CountTask> subTaskList = new ArrayList<>();
                long pos = start; //每个任务的起始位置
                for (int i = 0; i < TASKNUM; i++) {
                    long lastOne = pos + step; //每个任务的结束位置
//调整最后一个任务的结束位置
                    if ( lastOne > end ){

                        lastOne = end;
                    }
//创建子任务
                    CountTask task = new CountTask(pos, lastOne);
//把任务添加到集合中
                    subTaskList.add(task);
//调用 for()提交子任务
                    task.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(0L, 200000L);
//把大任务提交给线程池
        ForkJoinTask<Long> result = forkJoinPool.submit(task);
        try {

            Long res = result.get(); //调用任务的 get()方法返回结果
            System.out.println("计算数列结果为:" + res);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
//验证
        long s = 0L;
        for (long i = 0; i <= 200000 ; i++) {
            s += i;
        }
        System.out.println(s);
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值