鉴于我有一个字符串列表List<String> toProcess。结果必须按照原始行的顺序排列。我想利用新的并行流。
List<String> toProcess
以下代码是否 保证 结果的顺序与原始列表中的顺序相同?
// ["a", "b", "c"] List<String> toProcess; // should be ["a", "b", "c"] List<String> results = toProcess.parallelStream() .map(s -> s) .collect(Collectors.toList());
是的,订单得到保证。
出发点是看什么决定减少是否同时发生。Stream.collect()的描述如下:
Stream.collect()
如果该流是并行的,并且Collector是并发的,或者该流是无序的或收集器是无序的,那么将执行并发缩减(请参阅Collector有关并发缩减的详细信息。)
Collector
满足第一个条件:流是并行的。第二个和第三个如何:Collector并发和无序?
toList()的文档内容如下:
toList()
返回一个Collector,将输入元素累积到一个new中List。无法保证返回的类型,可变性,可序列化性或线程安全性List;如果List需要对返回的内容进行更多控制,请使用toCollection(Supplier)。 返回: 一个收集器, 以遇到的顺序 将所有输入元素收集到一个List 中
返回一个Collector,将输入元素累积到一个new中List。无法保证返回的类型,可变性,可序列化性或线程安全性List;如果List需要对返回的内容进行更多控制,请使用toCollection(Supplier)。
List
toCollection(Supplier)
返回: 一个收集器, 以遇到的顺序 将所有输入元素收集到一个List 中
以相遇顺序工作的操作按其原始顺序对元素进行操作。这将覆盖并行性。
检查实施Collectors.java确认toList()并 没有 包含CONCURRENT或UNORDERED特征。
Collectors.java
CONCURRENT
UNORDERED
public static <T> Collector<T, ?, List<T>> toList() { return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add, (left, right) -> { left.addAll(right); return left; }, CH_ID); } // ... static final Set<Collector.Characteristics> CH_ID = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
注意收集器如何具有CH_ID特征集,该特征集仅具有单个IDENTITY_FINISH特征。CONCURRENT并且UNORDERED不存在,因此减少不能并发。
CH_ID
IDENTITY_FINISH
非并行减少意味着,如果流是并行的,则收集可以并行进行,但是它将被拆分为多个线程限制的中间结果,然后将其合并。这样可以确保组合结果按相遇顺序排列。