Fork-join思路就是将大任务拆分成小任务,在分别计算出结果,最后进行汇总

在简单的分治编程不适合的情况下,推出了ForkJoinPool线程池

在普通的线程池中,如果想要采用分治的思想

那么在将大任务分成小任务的时候,就会将大任务的线程进行阻塞,导致了任务无法正常运行下去

而且线程池自带的大小会导致一件事,就是当阻塞的线程达到了总线程数,那么直接无法执行了

而ForkJoinPool线程则是

加入了工作窃取的算法,即work-stealing算法

工作窃取算法简单来说,就是某个线程从其他线程窃取任务来执行

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

图片

在线程池中,整个任务分为了外部任务和内部任务

外部任务就是全局队列中的大任务

内部任务则是拆分完成后放在内部队列中的数据

线程切割完成的任务就放在其中,去用于存放

这样的执行流程就是,拿到子任务的计算结果,先判断是否完成,在判断是否被其他队列窃取了,如果都没有就执行

不然就去执行下一个任务

最后这个队列中都执行完成了,就去扫描其他队列的任务,尝试窃取

工作窃取的优点

线程不会因为空了而被阻塞,会高效的进行利用,直到所有的任务都为空,才会阻塞挂起

提供高效的并行性能,不会因为互斥而导致性能上不去

接下来关于整个框架的介绍

首先是三个核心类

ForkJoinPool,线程池

ForkJoinWorkerThread,执行工作的线程,维持了一个内部队列

ForkJoinTask,任务抽象类,实现了Future接口

通常的使用是继承其两个子类

RecursiveTask: 子任务带返回结果时使用

RecursiveAction: 子任务不带返回结果时使用

模式基本为

if 任务足够小

直接返回结果

else

分割成N个子任务

依次调用每个子任务的fork方法执行子任务

依次调用每个子任务的join方法合并执行结果

发表评论

邮箱地址不会被公开。 必填项已用*标注