浅谈Java的ForkJoin

1.什么是ForkJoin?

ForkJoin是由JDK1.7后提供多线并发处理框架,ForkJoin的框架的基本思想是分而治之。使用ForkJoin将相同的计算任务通过多线程的进行执行。从而能提高数据的计算速度。通过多线程提高大数据的处理。处理大数据是使用ForkJoin的前提,数据较小时不建议使用!

2.主要思想

分而治之:ForkJoin将一个复杂的任务,按照设定的阈值进行分解成多个子任务,然后将各个子任务结果进行汇总。如图:当然实际就按阈值来拆分子任务
在这里插入图片描述
3.使用

  • 使用ForkJoin框架,需要创建一个ForkJoin的任务。因为ForkJoin框架为我们提供了RecursiveAction和RecursiveTask。我们只需要继承ForkJoin为我们提供的抽象类的其中一个并且实现compute方法。
  • RecursiveTask在进行exec之后会使用一个result的变量进行接受返回的结果。
  • 而RecursiveAction在exec后是不会保存返回结果。

使用步骤:
1.FrokJoin需要用过forkJoinPool来执行
2.再计算任务forkJoinPool.execute或者forkJoinPool.sumbit
3.计算类需要继承RecursiveTask或RecursiveAction

代码示例:计算0~10_0000_0000相加的值

package com.kuang.forkjoin;

import java.util.concurrent.RecursiveTask;

public class ForkJoinDemo extends RecursiveTask<Long> {
    private Long start;
    private Long end;

    //临界值
    private Long temp = 10000L;

    public ForkJoinDemo(Long start, Long end) {
        this.start = start;
        this.end = end;
    }

    //计算方法
    @Override
    protected Long compute() {
       if((end-start)<temp){
           Long sum = 0L;
           for (long i = start;  i<= end; i++) {
               sum += i;
           }
           return sum;
       }else{
           //forkjoin
           long middle = (start+end)/2;
           ForkJoinDemo task1 = new ForkJoinDemo(start, middle);
           task1.fork();
           ForkJoinDemo task2 = new ForkJoinDemo(middle+1, end);
           task2.fork();
           return task1.join() + task2.join();
       }
    }
}

测试类:

package com.kuang.forkjoin;

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

public class SumTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        test1();//5479
        test2(); //4011

    }


    //普通方法
    public static void test1(){
        Long sum = 0L;
        long start = System.currentTimeMillis();
        for (long i = 1; i <= 10_0000_0000; i++) {
            sum += i;
        }
        long end = System.currentTimeMillis();
        System.out.println("sum:"+sum+" "+(end-start));
    }

    //ForkJoin框架
    public static void test2() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinDemo task = new ForkJoinDemo(0L, 10_0000_0000L);
        ForkJoinTask<Long> submit = forkJoinPool.submit(task);
        final Long sum = submit.get();
        long end = System.currentTimeMillis();
        System.out.println("sum:"+sum+" "+(end-start));
    }
 
}

测试结果:
在这里插入图片描述
在这里插入图片描述
明显效率提高了!

4.特点:工作窃取

  • 任务进行分解成多个子任务的时候,每个子任务的处理时间都不一样。

  • 例如分别有子任务A和B。如果子任务B某一时刻已经执行完毕,子任务A还在执行。那么如果子任务B的线程等待子任务A完毕后在进行汇总,那么子任务B线程就会在浪费执行时间,最终的执行时间就以最耗时的子任务为准。

  • 而如果子任务B执行完毕后,处理子任务A的任务,并且执行完毕后将任务归还给子任务A。这样就可以提高执行效率,这就是工作窃取。
    在这里插入图片描述
    不过有时子任务B去窃取子任务B的任务时,子任务A也刚好执行到那个任务,两者就会发生争夺,这是它的弊端

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值