1)概念
Fork/Join 是JDK1.7加入的新的线程池实现,它体现的是一种分治思想,适用于能够进行任务拆分的cpu密集型运算。
任务拆分是指:将一个大任务拆分为算法上相同的小任务,直至不能拆分可以直接求解。跟递归相关的一些计算,如归并排序、斐波那契数列、都可以用分治思想进行求解。
Fork/Join在分治的基础上加入了多线程,可以把每个任务的分解和合并交给不同的线程来完成,进一步提升运算效率
简单讲,一个任务被分配给多个线程去执行。
Fork/Join默认会创建与cpu核心数大小相同的线程池,所以称之为密集型运算(cpu核心被完全利用)
2)使用
以计算数字累加和为例,阐述fork/join线程池工作原理:
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import org.slf4j.*;
public class TestForkJoin {
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool(4);
System.out.println(pool.invoke(new MyTask(5)));
}
}
class MyTask extends RecursiveTask<Integer>{
public MyTask(int n) {
this.n = n;
}
private int n;
@Override
protected Integer compute() {
if (n==1){
System.out.println(n);
return n;
}
//任务拆分
MyTask t1 = new MyTask(n-1);
t1.fork();//提交给其它线程去完成t1任务
//合并解雇
int result = n+t1.join();
return result;
}
}
如上例代码,ForkJoinPool线程池创建后,向其提交的任务类型不再是Runnable/Callable,而是需要自定义Task类继承RecursiveTask类或RecursiveAction类;
- 继承RecursiveTask类,需要extends RecursiveTask
,指定任务的返回类型; - 继承RecursiveAction类,表示任务无返回值;
本例中,compute方法为任务执行的代码,在任务中手动将任务再划分是fork/join线程池的思想。实现方法是fork()与join()方法。在任务代码中再创建一个子任务对象,调用该对象的fork方法再启动一个线程去执行此子任务,并通过该子任务对象的join方法返回结果。
从流程图可以看出,任务的多个线程之间还是串行执行,上层任务需要等待下层任务执行并返回结果;