最近在看 JUC线程池: Fork/Join框架详解,就尝试地写一个案例尝试下。
Fork/Join 的分治思想: 把大任务拆分(Fork)为多个小任务,这些小任务会在新的线程中执行,最后同步等待划分的小任务都执行结束后,获取他们的结果做一个合并(Join)操作返回。这或学有点像 Hadoop 的 MapReduce 计算框架,不过不同的是,MapReduce 的 大任务 拆分是迭代的,只能第一个Map 阶段全部走完才能继续下一个阶段Map或Reduce;但 Fork/Join 是可以递归操作的,一个小任务可以再拆分多多个更小的任务。
说到这,既然是分治模式,那就很切合排序算法中的 归并排序了,对吧,因此我就试了下把自己原来写的普通归并排序改成一个并行归并排序,即能利用多个线程执行。
设计思路
写的时候发现很简单,原来的代码不用改太多都可以直接使用。
- 把需要被排序的数组存入到一个 ForkJoinTask 对象中,把这个对象提交给 ForkJoinPool 执行,调用 ForkJoinTask 的 get() 方法 同步等待排好序的数组即可。
- 设计时,我们需要实现一个 ForkJoinTask 的子类——ParallelMergeSortTask,用来封装我们的 fork/join 逻辑和归并排序代码,我们继承 RecursiveTask 抽象类(它也是 ForkJoinTask 的子类,使用它我们能少实现点方法),泛型 T 即使我们 get() 返回的类型
- 为了编写方便,这里使用的数组类型是 int[],同样也可以改写为任何数组类型,double[]、<? extends Comparable>[],甚至是实现 RandomAccess 的 Collection(当然归并排序的细节需要改改)
- OK, 很简单,直接上代码了
源码
ParalleMergeSortTask
package com.onemsg.learn.juc;
import java.util.concurrent.RecursiveTask;
public class ParallelMergeSortTask extends RecursiveTask<int[]>{
private static final long serialVersionUID = 20200817L;
private int[] arr;
private int[] tempArray;
private int left;
private int right;
public ParallelMergeSortTask(int[] arr) {
this.arr = arr;
this.tempArray = new int[arr.length];
this.left = 0;
this.right = arr.length - 1;
}
private ParallelMergeSortTask(int[] arr, int[] tempArray, int left, int right){
this.arr = arr;
this.tempArray = tempArray;
this