.collect是否保证在并行流上排序?

时间:2015-04-17 23:22:21

标签: java list java-8

鉴于我有一个字符串列表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());

2 个答案:

答案 0 :(得分:49)

TL; DR

是的,订单有保证。

Stream.collect()API文档

起点是要确定减少是否并发的原因。 Stream.collect()的描述如下:

  

如果流是并行的,并且Collectorconcurrent,并且流是无序的或收集器是unordered,那么将执行并发减少(请参阅{{ 3}}有关并发减少的详细信息。)

满足第一个条件:流是并行的。第二个和第三个怎么样:Collector并发和无序?

Collectors.toList()API文档

Collector的文档内容如下:

  

返回Collector,将输入元素累积为新的List。对List返回的类型,可变性,可序列性或线程安全性没有任何保证;如果需要对返回的List进行更多控制,请使用toCollection(Supplier)

     

返回:
  收集器将所有输入元素收集到List中,遇到顺序

toList()中运行的操作以原始顺序对元素进行操作。这取代了并行性

实施代码

检查Collectors.java的实施情况,确认toList() 包含CONCURRENTUNORDERED特征。

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特征。 <{1}}和CONCURRENT不存在,因此减少不能同时发生。

非并发减少意味着,如果流是并行的,则集合可以并行进行,但是它将被分成几个线程限制的中间结果,然后进行组合。这确保了组合结果处于相遇状态

另请参阅: encounter order

答案 1 :(得分:6)

您可以保证获得遇到顺序的元素。

来自documentation of toList

  

返回:          收集器将所有输入元素收集到List中,遇到顺序

有关“遇到订单”一词的更多信息,请参阅java.util.streams summary

此外,List#spliterator文档要求List的所有实现都会生成ORDERED的分词符:

  

Spliterator报告Spliterator.SIZED和Spliterator.ORDERED。实施应记录其他特征值的报告。

奇怪的是,虽然List接口需要iterator()以“正确的顺序”生成元素,但spliterator()只需要排序,但不是特别要求遵循列表的自然顺序。

因此,为了回答您的问题,toList生成的列表保证包含与源列表的分裂器命令它们完全相同的元素。流是并行还是顺序无关紧要。