Java中并行执行任务的框架Fork/Join

  Fork/Join框架是Java7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干小任务,最终汇总每个小任务结果后得到大任务结果的框架。Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果。Fork/Join的运行流程如下:

Java中并行执行任务的框架Fork/Join_第1张图片

  Fork/Join计算框架的核心是ForkJoinPool这个类,它继承自AbstractExecutorService,实现了工作窃取算法:

Java中并行执行任务的框架Fork/Join_第2张图片

   工作窃取(work-stealing)算法是指某个线程从其他队列里窃取任务来执行。假如我们需要做一个比较大的任务,可以把这个任务分割为若干互不依赖的子任务,为了减少线程间的竞争,把这些子任务分别放到不同的队列里,并为每个队列创建一个单独的线程来执行队列里的任务,线程和队列一一对应。但是,有的线程会先把自己队列里的任务干完,而其他线程对应的队列里还有任务等待处理。干完活的线程与其等着,不如去帮其他线程干活,于是它就去其他线程的队列里窃取一个任务来执行。而在这时它们会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。

  Fork/Join框架可以概括为两个步骤来执行任务:

1、分割任务。首先我们需要有一个fork类来把大任务分割成子任务,有可能子任务还是很大,所以还需要不停地分割,直到分割出的子任务足够小。

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

以上两个步骤主要是通过ForkJoinTask和ForkJoinPool这两个类来完成的:

ForkJoinTask:我们要使用Fork/Join框架,必须首先创建一个Fork/Join任务。它提供在任务中执行fork()和join()操作的机制。通常情况下,我们不需要直接继承ForkJoinTask类,只需要继承它的子类,Fork/Join框架提供了以下两个子类,RecursiveAction:用于没有返回结果的任务;RecursiveTask:用于有返回结果的任务。

ForkJoinPool:ForkJoinTask需要通过ForkJoinPool来执行。

对于Fork/Join框架的使用,需要创建一个任务类,继承RecursiveAction或RecursiveTask抽象类,然后实现抽象方法compute()。

Java中并行执行任务的框架Fork/Join_第3张图片

Java中并行执行任务的框架Fork/Join_第4张图片

可以看出,一个有返回值,一个没有返回值。

关于Fork/Join框架的实现原理,最主要是ForkJoinTask的fork方法和join方法的实现原理。当我们调用ForkJoinTask的fork方法时,程序会调用ForkJoinWorkerThread工作队列的push方法异步地执行这个任务,然后立即返回结果。

Java中并行执行任务的框架Fork/Join_第5张图片

push方法把当前任务存放在ForkJoinTask数组队列里。然后再调用ForkJoinPool的signalWork()方法唤醒或创建一个工作线程来执行任务。

Java中并行执行任务的框架Fork/Join_第6张图片

ForkJoinTask的join方法的主要作用是阻塞当前线程并等待获取结果。

Java中并行执行任务的框架Fork/Join_第7张图片

这些都了解一下就好了,要想熟悉这个并发执行任务的框架,还需要在项目中各种场景多多运用,灵活运用。

你可能感兴趣的:(多线程)