Java Stream API - 理解 Java Stream 中的并行拆分
🎯 为什么要拆分?
在使用
parallelStream()时,Java 会尝试将数据源拆分成多个子任务并在多个 CPU 核心上并行处理。
因此,数据能否有效拆分,是决定并行流性能的关键因素之一!
🧩 拆分的三大标准
一个'适合拆分'的数据源,应具备:
- ✅ 拆得快:可以高效找到中间点
- ✅ 拆得平:能平均分配处理负载
- ✅ 可预测:能预估总量及子部分数据量
📦 常见集合的拆分能力分析
1️⃣ ArrayList —— 拆得快 & 拆得平 ✅✅✅
List<Integer> list = IntStream.range(0, 1_000_000).boxed().toList();
List<Integer> sub1 = list.subList(0, 500_000);
List<Integer> sub2 = list.subList(500_000, 1_000_000);
- 底层是数组结构
- 直接通过下标定位中间元素,毫无压力
- 非常适合并行流处理
🧠 类比:像切蛋糕,一刀下去刚好一半!
2️⃣ LinkedList —— 拆得慢 ⚠️
LinkedList<Integer> list = new LinkedList<>();
IntStream.range(0, 1_000_000).forEach(list::add);
- 想要找到中间节点,得走一半链表(O(n))
- 每次迭代都有大量 指针追踪(Pointer Chasing)
- 拆分性能差,不建议用作并行流的数据源
🧠 类比:像找书架中间那本书,但书只能一本本翻,效率极低。
3️⃣ HashSet —— 拆分难度中等 ⚠️
- 底层是散列桶数组(类似数组)
- 但桶中数据分布不均,拆了也可能'左多右少'
- 有时甚至一半桶为空,导致负载严重不均
🔍 拆分时难以平均切分工作量
4️⃣ TreeSet —— 拆得平,但有指针跳转 ⚠️✅
- 基于红黑树结构
- 拆成两个平衡子树是可行的
- 但访问节点仍需频繁指针跳转,影响性能
🧠 类比:像拆一个大树枝成两个分支,但分支里的果子不在一起。


