并发编程之三——JUC工具类

1. Fork-Join

1.1 分而治之

分治法的设计思想是:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。

分治策略是:对于一个规模为 n 的问题,若该问题可以容易地解决(比如说规模 n 较小)则直接解决,否则将其分解为 k 个规模较小的子问题,这些子问题互相独立且与原问题形式相同(子问题相互之间有联系就会变为动态规范算法)递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。

1.2 Fork-Join原理

并发编程之三——JUC工具类_第1张图片

1.3 Fork-Join实战

我们要使用 ForkJoin 框架,必须首先创建一个 ForkJoin 任务。它提供在任务中执行 fork join 的操作机制,通常我们不直接继承 ForkjoinTask 类,只需要直接继承其子类。

1. RecursiveAction,用于没有返回结果的任务;

2. RecursiveTask,用于有返回值的任务;

task 要通过 ForkJoinPool 来执行,使用 submit invoke 提交,两者的区别是:invoke 是同步执行,调用之后需要等待任务完成,才能执行后面的代码;submit 是异步执行。joinget 方法当任务完成的时候返回计算结果。

并发编程之三——JUC工具类_第2张图片

在我们自己实现的 compute 方法里,首先需要判断任务是否足够小,如果足够小就直接执行任务。如果不足够小,就必须分割成两个子任务,每个子任务在调用 invokeAll 方法时,又会进入 compute 方法,看看当前子任务是否需要继续分割成孙任务,如果不需要继续分割,则执行当前子任务并返回结果。使用 join方法会等待子任务执行完并得到其结果。

示例代码:

/**
 * forkjoin实现的归并排序
 */
public class FkSort {
    class SumTask extends RecursiveTask{

        // 当分解的任务阈值达到THRESHOLD时,不再对任务进行分解
        private final static int THRESHOLD = 2;
        private int[] src;

        public SumTask(int[] src) {
            this.src = src;
        }

        @Override
        protected int[] compute() {
            // 子数组个数不大于阈值,则用插入排序对子数组进行排序
            if(src.length<=THRESHOLD){
                // 最小的子任务采用插入排序
                return InsertionSort.sort(src);
            }else{
                //fromIndex....mid.....toIndex
                int mid = src.length / 2;
                // 将任务拆分成leftTask和rightTask
                SumTask leftTask = new SumTask(Arrays.copyOfRange(src, 0, mid));
                SumTask rightTask = new SumTask(Arrays.copyOfRange(src, mid, src.length));
                // 对拆分任务分别执行
                invokeAll(leftTask,rightTask);
                // 获取子任务结果
                int[] leftResult = leftTask.join();
                int[] rightResult = rightTask.join();
                // 合并子任务结果
                return MergeSort.merge(leftResult,rightResult);
            }
        }
    }
    
    /**
     * 插入排序
     */
    class InsertionSort{
        public static int[] sort(int[] array) {
            if (array.length == 0)
                return array;
            int currentValue;/*当前待排序数据,该元素之前的元素均已被排序过*/
            for (int i = 0; i < array.length - 1; i++) {
                int preIndex = i;/*已被排序数据的索引*/
                currentValue = array[preIndex + 1];

                /*在已被排序过数据中倒序寻找合适的位置,如果当前待排序数据比比较的元素要小,
                将比较的元素元素后移一位*/
                while (preIndex >= 0 && currentValue < array[preIndex]) {
                    //将当前元素后移一位
                    array[preIndex + 1] = array[preIndex];
                    preIndex--;
                }
                /*while循环结束时,说明已经找到了当前待排序数据的合适位置,插入*/
                array[preIndex + 1] = currentValue;
            }
            return array;
        }
        
    }

    /**
     *归并排序
     */
    class MergeSort{
        /**
         * 归并排序——将两段排序好的数组结合成一个排序数组
         *
         * @param left
         * @

你可能感兴趣的:(java,java,多线程)