Fork-Join框架

把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。

F1

工作窃取算法

某个线程从其他队列里窃取任务来执行。使用的场景是一个大任务拆分成多个小任务,为了减少线程间的竞争,把这些子任务分别放到不同的队列中,并且每个队列都有单独的线程来执行队列里的任务,线程和队列一一对应。

然而依然会出现一种情况:线程A先把队列里的工作搞定了,而B还有一些任务,A帮B做任务,但如果两个线程访问同一个队列,会产生竞争,所以A想了一个办法,从双端队列的尾部拿任务执行。而B线程永远是从双端队列的头部拿任务执行(任务是一个个独立的小任务)。

F2.png
  • 优点:

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

  • 缺点:
    1. 如果双端队列中只有一个任务时,线程间会存在竞争。
    2. 消耗了更多的系统资源,如会创建多个线程和多个双端队列。

框架设计

  1. 分割任务

    使用fork类把大任务分割为小任务

  2. 执行任务合并结果

    分割的子任务分别放在双端队列里,启动线程从双端队列获取任务并执行。执行结果放在同一的一个队列,启动一个线程从队列里拿数据,然后合并

使用2个类完成以上事务:

  1. ForkJoinTask:提供在任务中执行fork和join操作的机制。一般情况下,我们并不需要直接继承ForkJoinTask类,只需要继承它的子类,它的子类有两个:
  • RecursiveAction:用于没有返回结果的任务。
  • RecursiveTask:用于有返回结果的任务。
  1. ForkJoinPool:任务ForkJoinTask需要通过ForkJoinPool来执行。

参见代码CountTask

异常处理

使用isCompletedAbnormally()检查任务是否已经抛出异常或者被取消,并且可以通过ForkJoinTask的getException()获取异常

实现原理

  • fork

    调用pushTask方法异步执行任务,然后返回,pushTask方法将当前任务存放在ForkJoinTask数组队列里,然后再调用ForkJoinPool的signalWork()唤醒或创建一个工作线程来执行任务

  • join

    主要作用是阻塞当前线程并等待获取结果,当中会调用doJoin()判断当前任务的状态

你可能感兴趣的:(Fork-Join框架)