forkJoin的使用

149 阅读3分钟

原理:

定义:一个并行计算框架

用途:解决分治算法中的大规模任务。Fork/Join框架是基于工作窃取算法(work-stealing)的。

Fork/Join框架的核心概念有两个:

1.Fork(分割):将一个大任务,划分成多个相互独立且较小的子任务,这些子任务可以并行的执行。当一个任务被分割成多个子任务后,他们会进入到线程池的等待队列中等待执行。

2.Join(合并):等待子任务的执行结果,并将子任务的结果合并成一个整体结果。通常,在等待子任务时,线程会暂时挂起,执行其他可用的任务。

主要类:

ForkJoinPool,RecusiveTask(用于有返回值的任务),RecusiveAction(用于无返回值的任务)。

ForkJoinPool类的方法:

  1. ForkJoinPool(int parallelism):构造一个指定并行度(即线程数)的 ForkJoinPool 对象。
  2. submit(ForkJoinTask<T> task):提交一个 Fork/Join 任务给线程池进行执行,并返回一个 ForkJoinTask 对象,可用于获取任务的执行结果或取消任务。
  3. execute(ForkJoinTask<?> task):以异步无返回值的方式执行一个 Fork/Join 任务。
  4. invoke(ForkJoinTask<T> task):同步地执行一个 Fork/Join 任务,并返回任务的结果。
  5. awaitTermination(long timeout, TimeUnit unit):阻塞当前线程,直到所有提交的任务执行完毕或超时。
  6. shutdown():平缓地关闭线程池,等待已提交的任务完成执行。
  7. shutdownNow():立即关闭线程池,尝试中断正在执行的任务并返回未执行的任务列表。
  8. getParallelism():获取当前线程池的并行度(即线程数)。
  9. getPoolSize():获取当前线程池中正在活动的线程数。
  10. getActiveThreadCount():获取当前线程池中正在执行任务的线程数。
  11. getQueuedTaskCount():获取当前线程池等待执行的任务数。
  12. getStealCount():获取当前线程池中发生的工作窃取次数。

这些方法只是 ForkJoinPool 类中的一部分,它还提供了其他一些方法用于管理和监控 Fork/Join 任务的执行。通过使用这些方法,可以更好地控制和优化 Fork/Join 任务的并行执行效果。

示例:

package com.springBatch.demo.forkjoinDemo;

import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.concurrent.RecursiveTask;

@EqualsAndHashCode(callSuper = true)
@Data
public class FibonacciTask extends RecursiveTask<Integer> {

    //3.定义执行任务的阈值
    private final int n;


    //2.重写比较方法
    @Override
    protected Integer compute() {
        //4.
        if (n <= 1) {
            return n;
        } else {
            FibonacciTask f1 = new FibonacciTask(n - 1);
            f1.fork();
            FibonacciTask f2 = new FibonacciTask(n - 2);
            return f2.compute()+f1.join();
        }

    }
}
package com.springBatch.demo.forkjoinDemo;

import java.util.concurrent.ForkJoinPool;

public class Demo {
    public static void main(String[] args) {
        int n=10;
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        FibonacciTask fibonacciTask = new FibonacciTask(n);
        Integer result = forkJoinPool.invoke(fibonacciTask);
        System.out.println("第"+n+"个斐波那契数列是:"+result);

    }
}

附录:

  • 分治算法:

    • 将一个大的问题,划分成许多小的子问题,然后递归的解决这些问题,最后将这些子问题的解,合并起来,得到最终的结果。
  • 分治算法包含以下步骤:

    • 分解(Divide):将原来的任务,分解成若干个规模更小且相互独立的子问题。
    • 解决(Conquer):递归的解决每个子问题。如果子问题,足够小,无需进一步划分,直接求解。
    • 合并(Combine):将各个子问题的解合并起来,得到原始问题的解。
  • 递归:

    • 定义:一种算法或者函数的实现方式,通过调用自身来解决问题。函数在执行过程中,需要解决一个相同但规模更小的子问题时,他会再次调用自身,并将子问题作为参数,传递给自己。

    • 递归通常包含两个部分:

      • 递归基(Base case):也称终止条件。当满足某些条件时,递归就不再继续,即不再进行递归调用自身,而是返回一个确定的值,终止递归过程。
      • 递归步骤(Recursive step):递归本质上是将原始问题划分成多个相似的子问题,并将这些问题,用相同的过程解决,每次递归调用会处理规模更小的子问题,直到达到递归终止条件为止。