ForkJoin框架采用了分治思想,fork-分,join-合,把大的计算任务分解成多级子任务,对每个末级子任务开辟线程处理,末级子任务再向上通过某种计算逻辑逐级合并成一个大任务。这样拆分节省了内存空间,多线程并发编程节省了计算时间。
在大数据领域有MapReduce框架,处理hdfs分布式存储的文件,而jdk1.7实现了ForkJoin框架,屏蔽多任务时的线程管理与分配细节,程序员只需要定义这个大任务,关注拆分与合并的逻辑。
***下面举对1亿个数排序的例子***
array是个1亿长度的数组,现在对它快速完成排序,采用归并排序:
排序具体实现写在自建的ArrayMergerSortTask.java中,自己定义的ArrayMergeSortTask需要继承ForkJoinTask类 的 RecursiveAction子类。
ArrayMergerSortTask.java:
- 用到ForkJoin框架中的ForkJoinPool线程池
- 重写RecursiveAction类中的compete()方法
大任务stask是对数组排序,那么如何定义这个排序任务ArrayMergerSortTask呢?
可以看到继承了RecursiveAction类
RecursiveAction是什么类呢?
ForkJoinTask类里面两个最主要子类:RecursiveTask和RecursiveAction,RecursiveTask有返回值,RecursiveAction 无返回值(void),从名字action可以看出,只是执行计算。
ForkJoinTask类是什么呢?
可以看到FrokJoinTask类实现了Future,Future我们都知道是异步的。
看下ForkJoinPool的sumbit()和InvokeAll()方法,线程池提交了大任务,。
找到ForkJoinPool.java里面:
- submit()
submit方法里面提交的任务是ForkJoinTask<T>的,呼应前面的继承ForkJoinTask的RecursiveAction。
- invokeAll()
invokeAll传两个任务。
等待一个异步的结果,两个任务根据计算逻辑合并后的结果。
ForkJoinPool中线程数量是Runtime.getRuntime().availableProcessors(),处理器的数量。因为ForkJoin框架用于处理繁重的计算,计算密集型任务不需要很多线程。
总结:看了ForkJoin框架中ForkJoinPool.java与ForkJoinTask.java两个模块。框架里面对多线程并发进行管理,把拆分、什么时候开启新一轮合并、管理线程和内存等难点都实现了,而我们只需要关注做什么计算任务,任务怎么拆分的逻辑。