0
点赞
收藏
分享

微信扫一扫

深入理解并发编程之线程池Fork Join

夜空一星 2022-02-17 阅读 41

深入理解并发编程之线程池Fork Join

文章目录


一、什么是Fork Join

或许初级程序员不知道什么是Fork Join,我们先简单的举个例子来说明下:

Fork Join是Java7提供的并行执行任务的框架,是一个把大任务分割成若干小任务,小任务可以继续不断拆分n多个小任务,最终汇总小任务的结果得到大任务结果的框架。

二、举例说明下Fork Join的用法

我们用3个线程的Fork Join线程池求1到10W的和来简单的看一下:

public class ForkJoinTest extends RecursiveTask<Long> {
    private Long start;		//计算的开始值
    private Long end;		//计算的最终值
    private Long max = 100L; //计算区间的最大差值
    private static AtomicInteger worker1 = new AtomicInteger(0); //分别记录每个线程执行次数
    private static AtomicInteger worker2 = new AtomicInteger(0);
    private static AtomicInteger worker3 = new AtomicInteger(0);


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

    @Override
    protected Long compute() {
        Long sum = 0L;
        //如果计算的区间小于100直接计算
        if (end - start < max) {
            if ("ForkJoinPool-1-worker-1".equals(Thread.currentThread().getName())) {
                worker1.incrementAndGet(); //如果线程1执行就++
                System.out.println("worker1:" + worker1.get());
            }
            if ("ForkJoinPool-1-worker-2".equals(Thread.currentThread().getName())) {
                worker2.incrementAndGet(); //如果线程2执行就++
                System.out.println("worker2:" + worker2.get());
            }
            if ("ForkJoinPool-1-worker-3".equals(Thread.currentThread().getName())) {
                worker3.incrementAndGet(); //如果线程3执行就++
                System.out.println("worker3:" + worker3.get());
            }
            for (Long i = start; i <= end; i++) {
                sum += i;
            }
        } else {
            // 如果计算的区间>=100,分两半继续分直到分的区间小于100为止
            Long l = (start + end) / 2; 
            ForkJoinTest left = new ForkJoinTest(start, l);  //执行前面的一半
            //Fork()方法 Fork()方法类似于Thread.start(),但是它并不立即执行任务,而是将任务放入工作队列中,拆分子任务。
            left.fork();
            ForkJoinTest rigt = new ForkJoinTest(l + 1, end); //执行后面的一半
            rigt.fork();
            try {
                sum = left.get() + rigt.get(); //每一半的最终结果加起来
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        return sum;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ForkJoinTest forkJoinTest = new ForkJoinTest(1L, 10000L);
        ForkJoinPool forkJoinPool = new ForkJoinPool(3); //线程池有3个线程
        ForkJoinTask<Long> submit = forkJoinPool.submit(forkJoinTest);
        System.out.println("执行结果为:" + submit.get());
    }
}

可以看一下计算结果:
在这里插入图片描述
不考虑线程的话我们仔细看一下上面代码的逻辑,其实就是一个递归操作,我们一直往下递归把10000拆分成每部分都区间小于100的多个部分进行计算,然后把最后的和汇总起来。其实Fork Join就是使用多线程的递归,首先设置个预期值,如果在预期值内直接执行,如果不在预期值内则继续递归,往下继续递归任务。
在这里插入图片描述
Fork Join有三种提交任务的方式:

  • 通过invoke方法提交的任务,调用线程直到任务执行完成才会返回,也就是说这是一个同步方法,且有返回结果;
  • 通过execute方法提交的任务,调用线程会立即返回,也就是说这是一个异步方法,且没有返回结果;
  • 通过submit方法提交的任务,调用线程会立即返回,也就是说这是一个异步方法,且有返回结果(返回Future实现类,可以通过get获取结果

内容来源:蚂蚁课堂

举报

相关推荐

0 条评论