Arrays 类是 Java 中用于操作数组的工具类,提供了一系列实用的方法来处理数组。在 Java8 中,为 Arrays 类添加了许多并行化的操作,下面将详细说明。
Arrays.parallelSort 是 Java8 中引入的一个用于对数组进行并行排序的方法。它使用了并行排序-合并(sort-merge)算法,可利用多核 CPU 来提高排序的速度。
Arrays.parallelSort 方法存在以下特性:
并行处理:通过将数组划分为子数组,并在多个线程中对这些子数组进行排序和合并,从而实现并行排序。为了执行并行任务,它使用了 Fork/Join 框架(ForkJoinPool)。
自动选择算法:会根据数组的大小和运行环境自动决定是否使用并行排序。如果数组大小小于或等于某个临界值(通常为 8192,即 1 << 13),或者处理器只有一个核心,则会使用顺序的双轴快速排序(Dual-Pivot Quicksort)算法;否则,使用并行排序。
注意:使用并行排序在处理大规模数据时通常可以显著提高性能,但在数据量较小时,可能单线程的排序(如 Arrays.sort)会更快。
例如:使用 Arrays.parallelSort 静态方法对大数组进行排序。
// 初始化一个大 int 数组 int[] data = new int[10000]; for(int i = 0; i < data.length; i++) { data[i] = (int)(Math.random() * 10000); } // 对数组排序 Arrays.parallelSort(data); // 输出排序后的结果 System.out.println(Arrays.toString(data));
上述示例,将采用递增的顺序对数组进行排序(默认),我们可以使用自定义的 Comparator 接口实现递减的顺序对数组排序,例如:
// 初始化一个大 int 数组 Integer[] data = new Integer[10000]; for(int i = 0; i < data.length; i++) { data[i] = (int)(Math.random() * 10000); } // 对数组排序 Arrays.parallelSort(data, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); // 输出排序后的结果 System.out.println(Arrays.toString(data));
注意:如果你仔细观察,你会发现这些方法的名称中都带有 parallel(平行的;相似的,同时发生的;(计算机)并行的;并联的),毕竟用户并不关心排序是如何实现的。不过,API 的设计者们希望清晰地表示这些排序方法是并行执行的。这样就可以起到提示作用,避免比较器带来的副作用。
Arrays.parallelSetAll 方法用于并行地设置指定数组的所有元素,它使用提供的生成器函数来计算每个元素的值。该方法有多种签名形式,如下:
static void parallelSetAll(double[] array, IntToDoubleFunction generator) 并行设置指定数组的所有元素,使用提供的生成器函数计算每个元素。
static void parallelSetAll(int[] array, IntUnaryOperator generator) 并行设置指定数组的所有元素,使用提供的生成器函数计算每个元素。
static void parallelSetAll(long[] array, IntToLongFunction generator) 并行设置指定数组的所有元素,使用提供的生成器函数计算每个元素。
static <T> void parallelSetAll(T[] array, IntFunction<? extends T> generator) 并行设置指定数组的所有元素,使用提供的生成器函数计算每个元素。
示例:
修改 Arrays.parallelSort 方法的示例,使用 Arrays.parallelSetAll 方法重写初始化数组的部分,如下:
// 初始化一个大 int 数组 Integer[] data = new Integer[10000]; Arrays.parallelSetAll(data, new IntFunction<Integer>() { @Override public Integer apply(int value) { return (int)(Math.random() * 10000); } }); // 对数组排序 Arrays.parallelSort(data, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); // 输出排序后的结果 System.out.println(Arrays.toString(data));
Arrays.parallelPrefix 方法用于在给定的运算符基础上并行地更新数组。它会对数组的元素进行累积计算,并直接修改原始数组。这是什么意思?以下是一个示例。假设有数组 [1,2,3,4,...] 及乘法操作 x。当执行完 Arrays.parallelPrefix(values, (x, y) -> x * y ) 后,数组中包括:
[1, 1x2, 1×2×3, 1x2×3×4, ...]
parallelPrefix 方法有多种重载形式,如下:
static void parallelPrefix(double[] array, DoubleBinaryOperator op) 使用提供的函数并行累加给定数组中的每个元素。
static void parallelPrefix(double[] array, int fromIndex, int toIndex, DoubleBinaryOperator op) 为给定的数组子范围执行 parallelPrefix(double[], DoubleBinaryOperator)。
static void parallelPrefix(int[] array, IntBinaryOperator op) 使用提供的函数并行累加给定数组中的每个元素。
static void parallelPrefix(int[] array, int fromIndex, int toIndex, IntBinaryOperator op) 为给定的数组子范围执行 parallelPrefix(int[], IntBinaryOperator)。
static void parallelPrefix(long[] array, LongBinaryOperator op) 使用提供的函数并行累加给定数组中的每个元素。
static void parallelPrefix(long[] array, int fromIndex, int toIndex, LongBinaryOperator op) 为给定的数组子范围执行 parallelPrefix(long[], LongBinaryOperator)。
static <T> void parallelPrefix(T[] array, BinaryOperator<T> op) 使用提供的函数并行累加给定数组中的每个元素。
static <T> void parallelPrefix(T[] array, int fromIndex, int toIndex, BinaryOperator<T> op) 对给定数组的子范围执行 parallelPrefix(Object[],BinaryOperator)。
示例:
int[] data = {1,2,3,4,5}; // 并发更新数组 Arrays.parallelPrefix(data, new IntBinaryOperator() { @Override public int applyAsInt(int left, int right) { return left * right; } }); System.out.println(Arrays.toString(data)); //结果: //[1, 2, 6, 24, 120] //其中: // 1*2=2 // 1*2*3=6 // 1*2*3*4=24 // 1*2*3*4*5=120