JEP 103:并行数组排序
概述
向 java.util.Arrays
添加额外的实用方法,这些方法使用 JSR 166 的 Fork/Join 并行通用池来提供数组的并行排序功能。
非目标
有许多用于并行数组排序的算法,它们在时间和空间上有着不同的权衡。这里的目标是提供一个通常有用的实用操作,而不是提供一个让程序员可以选择不同算法的框架。
成功指标
在双核系统上,对于适当大小的数据集,相较于顺序排序,速度提升至少达到 1.3 倍。
动机
Java 7 增加了 Fork/Join 框架以实现轻量级的数据并行处理,但用户目前必须为简单或常见的任务自行实现算法。本提案通过提供数组的并行排序来解决一个常见任务。通过与数组之间的转换,该方法还可以用于对任意集合进行排序(对于那些具有定义好的遍历顺序的集合)。
描述
当前由 Java 集合框架(Collections.sort
和 Arrays.sort
)提供的排序实现全部在调用线程中按顺序执行排序操作。此增强功能将提供与 Arrays
类当前所提供的相同的一组排序操作,但会使用 Fork/Join 框架的并行实现。这些新的 API 在调用线程方面仍然是同步的,因为在并行排序完成之前,线程不会继续执行后续操作。
该提案新增的实际排序 API 将利用 ForkJoinPool
的 commonPool(默认的 Fork/Join 池由 JEP 155 定义)。
public class Arrays {
...
public static void parallelSort(byte[] a) { ... }
public static void parallelSort(byte[] a, int fromIndex, int toIndex)
public static void parallelSort(short[] a) { ... }
public static void parallelSort(short[] a, int fromIndex, int toIndex)
{...}
...
}
除 boolean
类型外,所有原始数组类型、Comparable
对象类型以及使用提供的 Comparator
的任意 Object 类型都定义了排序方法。排序算法采用的是 Doug Lea 在 ParallelArray
实现中使用的算法,并且需要一个与待排序数组大小相同的工作空间(这是指整个数组,而不仅仅是待排序的部分)。
开放问题:
- 一些用户是否需要指定使用哪个池的功能?
- 用户是否希望选择算法以允许空间/时间的权衡?
替代方案
没有考虑通用的替代方案。并行排序的实现来自于 Doug Lea 的 ParallelArray
框架。已经考虑了 API 的一些变化,特别是关于使用哪个线程池的问题,但目前认为这些变化比实际需要的更为复杂。
测试
- 包含从
Arrays.sort
的现有测试改编而来的单元测试 - 还包括展示出比串行排序速度提升的简单基准测试。
- 性能回归测试需要较大的(8 核以上)系统。
风险与假设
假定选择 Fork/Join 全系统共用的通用池,以及将此 API 与该池关联不会有争议(或者至少不会到阻止本提案进展的程度)。可以在稍后的阶段增加扩展 API 的能力,以允许进一步控制该池。
这里还假设,对于一般使用场景而言,简单的算法选择就足够了。
影响
- 兼容性:仅向前兼容
- 安全性:基于共享资源(系统 fork/join 池)提供更多 DoS 攻击
- 文档:仅提供 Javadoc
- 国际化:与现有的串行排序相比未改变。