Fork/Join 框架简介

执行器框架

执行器框架采用了一个线程池,该线程池可以执行你发送给执行器的任务,并且针对多个任务重用这些线程。

这种机制为程序设计人员提供了如下便利。

分治算法

分治算法是一种非常流行的设计方法。为了采用这种方法解决问题,要将问题划分为较小的问题。

可以采用递归方式重复该过程,直到需要解决的问题变得很小,可以直接解决。
必须很小心地选择可直接解决的基本用例,问题规模选择不当会导致糟糕的性能。
这种问题可以使用执行器解决,但是为了更高效地解决问题,Java 7 并发 API 引入了 Fork/Join 框架。

该框架基于 ForkJoinPool 类,该类是一种特殊的执行器,具有 fork() 方法和 join() 方法两个操作(以及它们的不同变体),以及一个被称作工作窃取算法的内部算法。

Fork/Join 示例

Fork/Join 框架的基本特征

Fork/Join 框架必须用于解决基于分治方法的问题。
必须将原始问题划分为较小的问题,直到问题很小,可以直接解决。

有了这个框架,待实现任务的主方法便如下所示:

if ( problem.size() > DEFAULT_SIZE) {
	divideTasks();
	executeTask();
	taskResults = joinTasksResult();
	return taskResults;
} else {
	taskResults = solveBasicProblem();
	return taskResults;
}

该方法最大的好处是可以高效分割和执行子任务,并且获取子任务的结果以计算父任务的结果。

该功能由 ForkJoinTask 类提供的如下两个方法支持。

工作窃取算法

Fork/Join 框架还有另一个关键特性,即工作窃取算法。该算法确定要执行的任务。

当一个任务使用 join() 方法等待某个子任务结束时,执行该任务的线程将会从任务池中选取另一个等待执行的任务并且开始执行。
通过这种方式,Fork/Join 执行器的线程总是通过改进应用程序的性能来执行任务。

公用池

Java 8在 Fork/Join 框架中提供了一种新特性。
每个Java应用程序都有一个默认的 ForkJoinPool ,称作公用池

可以通过调用静态方法 ForkJoinPool.commonPool() 获得这样的公用池,而不需要采用显式方法创建(尽管可以这样做)。
这种默认的 Fork/Join 执行器会自动使用由计算机的可用处理器确定的线程数。
可以通过更改系统属性值 java.util.concurrent.ForkJoinPool.common.parallelism 来修改这一默认行为。

Fork/Join 框架的局限性

解决问题时必须要考虑到它的局限性,主要有如下几个方面。

Fork/Join 框架的组件

Fork/Join 框架包括四个基本类。