ForkJoinPool 是JDK 7加入的一个线程池类。Fork/Join 技术是分治算法(Divide-and-Conquer)的并行实现,它是一项可以获得良好的并行性能的简单且高效的设计技术。目的是为了帮助我们更好地利用多处理器带来的好处,使用所有可用的运算能力来提升应用的性能。

带着BAT大厂的面试问题去理解

  • Fork/Join主要用来解决什么样的问题?
  • Fork/Join框架是在哪个JDK版本中引入的?
  • Fork/Join框架主要包含哪三个模块? 模块之间的关系是怎么样的?
  • ForkJoinPool类继承关系?
  • ForkJoinTask抽象类继承关系? 在实际运用中,我们一般都会继承 RecursiveTask 、RecursiveAction 或 CountedCompleter 来实现我们的业务需求,而不会直接继承 ForkJoinTask 类。
  • 整个Fork/Join 框架的执行流程/运行机制是怎么样的?
  • 具体阐述Fork/Join的分治思想和work-stealing 实现方式?
  • 有哪些JDK源码中使用了Fork/Join思想?
  • 如何使用Executors工具类创建ForkJoinPool?
  • 写一个例子: 用ForkJoin方式实现1+2+3+…+100000?
  • Fork/Join在使用时有哪些注意事项? 结合JDK中的斐波那契数列实例具体说明。

Fork/Join框架简介

Fork/Join框架是Java并发工具包中的一种可以将一个大任务拆分为很多小任务来异步执行的工具,自JDK1.7引入。

三个模块及关系

Fork/Join框架主要包含三个模块:

  • 任务对象: ForkJoinTask (包括RecursiveTaskRecursiveActionCountedCompleter)
  • 执行Fork/Join任务的线程: ForkJoinWorkerThread
  • 线程池: ForkJoinPool

这三者的关系是: ForkJoinPool可以通过池中的ForkJoinWorkerThread来处理ForkJoinTask任务。

1
2
3
4
5
6
7
8
9
10
11
// from 《A Java Fork/Join Framework》Dong Lea
Result solve(Problem problem) {
if (problem is small)
directly solve problem
else {
split problem into independent parts
fork new subtasks to solve each part
join all subtasks
compose result from subresults
}
}

ForkJoinPool 只接收 ForkJoinTask 任务(在实际使用中,也可以接收 Runnable/Callable 任务,但在真正运行时,也会把这些任务封装成 ForkJoinTask 类型的任务),RecursiveTask 是 ForkJoinTask 的子类,是一个可以递归执行的 ForkJoinTask,RecursiveAction 是一个无返回值的 RecursiveTask,CountedCompleter 在任务完成执行后会触发执行一个自定义的钩子函数。

在实际运用中,我们一般都会继承RecursiveTaskRecursiveActionCountedCompleter 来实现我们的业务需求,而不会直接继承 ForkJoinTask 类。

核心思想:分治算法

核心思想:work-stealing(工作窃取)

Fokr/Join框架的执行流程

Fork/Join类关系

ForkJoinPool继承关系

ForkJoinTask继承关系

再深入理解

有哪些JDK源码中使用了Fork/Join思想?

数组工具类 Arrays 在JDK 8之后新增的并行排序方法(parallelSort)就运用了 ForkJoinPool 的特性。
还有 ConcurrentHashMap 在JDK 8之后添加的函数式方法(如forEach等)也有运用。

使用Executors工具类创建ForkJoinPool

Java8在Executors工具类中新增了两个工厂方法:

1
2
3
4
5
// parallelism定义并行级别
public static ExecutorService newWorkStealingPool(int parallelism);
// 默认并行级别为JVM可用的处理器个数
// Runtime.getRuntime().availableProcessors()
public static ExecutorService newWorkStealingPool();

关于Fork/Join异常处理

Fork/Join例子

采用Fork/Join来异步计算1+2+3+…+10000的结果

实现斐波那契数列