并行流在不同的操作下是否正常工作?
我正在阅读有关无国籍状态的文章,并在文档中遇到了这个问题:
如果流操作的行为参数是有状态的,则流管道结果可能是不确定的或不正确的。有状态 lambda(或实现相应功能接口的其他对象)是其结果取决于在执行流管道期间可能更改的任何状态的 lambda。
现在,如果我有一个字符串列表(比如说),然后尝试按以下方式使用并行流从中删除重复的字符串:strList
List<String> resultOne = strList.parallelStream().distinct().collect(Collectors.toList());
或者如果我们想要不区分大小写:
List<String> result2 = strList.parallelStream().map(String::toLowerCase)
.distinct().collect(Collectors.toList());
此代码是否存在任何问题,因为并行流会拆分输入,并且在一个块中不同并不一定意味着在整个输入中不同?
编辑(以下答案的快速摘要)
这是一个有状态操作,在有状态中间操作的情况下,并行流可能需要多次传递或大量缓冲开销。如果元素排序不相关,也可以更有效地实现。另外根据文档:distinct
distinct
对于有序流,不同元素的选择是稳定的(对于重复的元素,将保留遇到顺序中首先出现的元素。对于无序流,不做稳定性保证。
但是,在并行运行的有序流的情况下,distinct可能是不稳定的 - 这意味着它将在重复的情况下保留任意元素,而不一定是其他方面预期的第一个元素。distinct
从链接:
在内部,distinct() 操作保留了一个包含以前见过的元素的 Set,但它隐藏在操作中,我们无法从应用程序代码中获取它。
因此,在并行流的情况下,它可能会消耗整个流,或者可能使用CHM(类似)。对于有序的,最有可能的是使用或类似的结构。ConcurrentHashMap.newKeySet()
LinkedHashSet