4.3 ForkJoin_聚合任务结果

ForkJoin 聚合任务结果

概述

如果任务需要解决的问题大于预定的大小,那么需要将这个问题拆分成多个子任务,并使用Fork/Join来执行这些子任务。执行完成后原始线程获取到由这些子任务产生的结果,再将结果合并汇总。上一章节讨论了如何拆分成子任务并使用Fork/Join来执行,本章讨论如何合并子任务的结果。


本节用一个计算所有产品价格总和的示例来说明。用一个计算计算任务来计算产品的价格总和,如果任务需要计算产品的数量大于10,则将拆分这些元素为两部分,通过调用invokeAll方法来分配执行所拆分的任务,然后通过调用RecursiveTask的get方法取得拆分任务的计算结果,将任务的计算结果相加返回。如果任务需要计算的产品数小于10则直接计算价格总和返回。


示例代码如下:

public class JoinDemo {
    public static void main(String[] args){
        //生成产品数据
        System.out.println("main:生成产品数据");
        List<Product> products = new ArrayList<Product>(50000);
        double value = 0;
        for(int i=0; i<50000; i++){
            Product p = new Product();
            double price = (100*Math.random());
            value += price;
            p.setPrice(price);
            products.add(p);
        }
        System.out.println("main:产品数据价格总和:" + value);
        //创建TaskDemo对象来更新产品价格
        SumPriceTask task = new SumPriceTask(products,0,products.size());

        //创建ForkJoinPool对象,并启动
        System.out.println("main:创建ForkJoinPool对象,并启动");
        ForkJoinPool pool = new ForkJoinPool();
        pool.execute(task);

        System.out.println("main:输出线程池信息");
        do{
            System.out.println("main:线程数量:" + pool.getActiveThreadCount());
            System.out.println("main:偷窃数量:" + pool.getStealCount());
            System.out.println("main:并行级别:" + pool.getParallelism());

            try {
                TimeUnit.MICROSECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }while(!task.isDone());

        //关闭线程池
        System.out.println("main:关闭线程池");
        pool.shutdown();
        //等待线程执行完成
        try {
            pool.awaitTermination(1,TimeUnit.HOURS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //输出计算结果
        try {
            double sum = task.get();
            System.out.println("main:价格总和计算结果是:" + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("main:退出");
    }
}

class SumPriceTask extends RecursiveTask<Double>{

    private List<Product> products;
    private int first;
    private int last;

    SumPriceTask(List<Product> products, int first, int last) {
        this.products = products;
        this.first = first;
        this.last = last;
    }

    @Override
    protected Double compute() {
        if(last-first < 10){
            return sumPrice();
        }else{
            //如果大于10个元素,则进行拆分
            int middle = (last+first)/2;
            SumPriceTask t1 = new SumPriceTask(products,first,middle+1);
            SumPriceTask t2 = new SumPriceTask(products,middle+1,last);
            invokeAll(t1,t2);
            double result = 0;
            try {
                result = t1.get() + t2.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            return result;
        }
    }

    /** 计算价格总和 **/
    private double sumPrice(){
        double sum = 0;
        for(int i=first;i<last; i++){
            sum += products.get(i).getPrice();
        }
        return sum;
    }
}

程序运行日志如下:


main:生成产品数据
main:产品数据价格总和:2495194.7098017232
main:创建ForkJoinPool对象,并启动
main:输出线程池信息
main:线程数量:1
main:偷窃数量:0
main:并行级别:2
main:线程数量:2
main:偷窃数量:0
main:并行级别:2
main:线程数量:2
main:偷窃数量:0
main:并行级别:2
main:线程数量:2
main:偷窃数量:0
main:并行级别:2
main:关闭线程池
main:价格总和计算结果是:2495194.7098017237
main:退出


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值