ForkJoin

发布时间 2023-03-22 22:18:43作者: 深海11

一、ForkJoin 分治思想:将大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。

二、ForkJoin特性:

1. ForkJoinPool不是为了替代ExecutorService,而是它的补充,在某些应用场景下性能比ExecutorService更好。

2. ForkJoinPool主要用于实现“分而治之”的算法,特别是分治之后递归调用的函数,例如 quick sort等。

3. ForkJoinPool最适合的是计算密集型的任务,如果存在IO,线程间同步,sleep()等会造成线程长时间阻塞的情况时,最好配合使用ManagedBlocker.

工作示意图:

1. 每个线程都有独立的双端队列(Deque:两头都可进可出)

2. 线程1处理完自身队列中的任务后,可以获取线程0的队列中的任务来处理

3. 线程操作自身的队列,是使用的push方法,从队尾插入,且从队尾取;线程操作其他线程的队列,采用的是poll.从队头取任务

三、ForkJoinPool源码解析

```

public ForkJoinPool(int parallelism,
ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler,
boolean asyncMode) {
this(checkParallelism(parallelism),
checkFactory(factory),
handler,
asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
"ForkJoinPool-" + nextPoolId() + "-worker-");
checkPermission();
}

```

parallelism:并行度,默认情况下跟我们机器的cpu的个数保持一致,使用Runtime.getRuntime().availableProcessors()可以得到我们机器运行时可用的cpu个数。
factory:创建新线程的工厂,默认情况下使用ForkJoinWorkerThreadFactory 
handler: 线程异常情况下的处理器,该处理器在线程执行任务时由某些无法预料到的错误而导致任务线程中断时进行一些处理,默认情况为null.
asyncMode: 这个参数要注意,在ForkJoinPool中,每一个工作线程都有一个独立的任务队列,asyncMode表示工作线程内的任务队列是采用何种方式进行调度,可以是先进先出FIFO,也可以是后进先出LIFO。如果为true,则线程池中的工作线程使用先进先出方式进行任务调度,默认情况下是false.

四、fork/join的使用

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

        RecursiveAction:用于没有返回结果的任务。(比如写数据到磁盘,然后就退出了。一个RecursiveAction可以把自己的工作分割成更小的几块,这样它们可以由独立的线程或CPU执行。我们可以通过继承来实现一个RecursiveAction).

         RecursiveTask:用于有返回结果的任务。(可以将自己的工作分割成若干更小任务,并将这些子任务的执行合并到一个集体结果。可以有几个水平的分割和合并)。

        CountedCompleter:在任务完成执行后会触发执行一个自定义的钩子函数。