8.3J.U.C-ForkJoin

Fork/Join框架是Java7提供的一个用于并行执行任务的框架,它是把大任务切分为若干个小任务执行的框架

它采用的主要是工作窃取算法,某个线程从其他队列里窃取任务来执行

被窃取队列的线程从双端队列的头部获取任务来执行,窃取队列的线程从双端队列的尾部获取任务来执行

优点:

充分利用线程进行并行计算,减少了线程之间的竞争

缺点

消耗了更多的系统资源,创建了多个线程和双端队列

Fork/Join框架的局限性

  • 任务只能使用fork和join作为同步机制,通过他们使用了其他同步机制,那么在同步时,工作线程就不能执行其他任务了

  • 拆分的任务不应该执行IO操作

  • 任务不能抛出检测异常,有异常必须通过代码处理

ForkJoin框架的两个核心类

  • ForkJoinPool

  • ForkJoinTask

package com.moluo.concurrency.aqs;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;

public class ForkJoinTaskExample extends RecursiveTask<Integer> {

    public static final int threshold = 2;
    private int start;
    private int end;

    public ForkJoinTaskExample(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        int sum = 0;

        // 如果任务足够小就计算任务
        boolean canCompute = (end - start) <= threshold;
        if (canCompute) {
            for (int i = start; i <= end; i++) {
                sum += i;
            }
        } else {
            // 如果任务大于阈值,就分裂成两个子任务执行
            int middle = (start + end) / 2;
            ForkJoinTaskExample leftTask = new ForkJoinTaskExample(start, middle);
            ForkJoinTaskExample rightTask = new ForkJoinTaskExample(middle + 1, end);

            // 执行子任务
            leftTask.fork();
            rightTask.fork();

            // 等待任务执行结束后合并其结果
            int leftResult = leftTask.join();
            int rightResult = rightTask.join();

            // 合并子任务
            sum = leftResult + rightResult;
        }
        return sum;
    }

    public static void main(String[] args) {
        ForkJoinPool forkJoinPool = new ForkJoinPool();

        // 生成一个计算任务
        ForkJoinTaskExample task = new ForkJoinTaskExample(1, 100);

        // 执行一个任务
        Future<Integer> result = forkJoinPool.submit(task);

        try {
            System.out.println("result: " + result.get());
        } catch (Exception e) {
            System.out.println("exception: " + e);
        }
    }
}

Last updated

Was this helpful?