请参阅下面的简单示例,该示例计算列表中每个单词的出现次数:
Stream<String> words = Stream.of("a", "b", "a", "c");
Map<String, Integer> wordsCount = words.collect(toMap(s -> s, s -> 1,
(i, j) -> i + j));最后,wordsCount是{a=2, b=1, c=1}。
但是我的流非常大,我想并行化作业,所以我写到:
Map<String, Integer> wordsCount = words.parallel()
.collect(toMap(s -> s, s -> 1,
(i, j) -> i + j));但是,我注意到wordsCount是一个简单的HashMap,所以我想知道是否需要显式地请求并发映射以确保线程安全:
Map<String, Integer> wordsCount = words.parallel()
.collect(toConcurrentMap(s -> s, s -> 1,
(i, j) -> i + j));可以与并行流一起安全地使用非并发收集器,还是应该仅在从并行流进行收集时使用并发版本?
发布于 2014-04-29 16:36:32
如果所有收集器遵循规范中的规则,则所有收集器都可以安全地并行或顺序运行。并行准备是这里设计的关键部分。
并发收集器和非并发收集器之间的区别与并行化的方法有关。
普通(非并发)收集器通过合并子结果来操作。因此,源被划分成一组块,每个块被收集到一个结果容器中(比如一个列表或映射),然后子结果被合并到一个更大的结果容器中。这是安全和维持秩序的,但对于某些类型的容器--特别是地图--可能很昂贵,因为按键合并两个映射通常很昂贵。
相反,并发收集器创建一个结果容器,其插入操作保证线程安全,并从多个线程向其发送元素。对于像ConcurrentHashMap这样高度并发的结果容器,这种方法可能比合并普通HashMaps更好。
因此,并发收集器比普通收集器严格优化。而且它们并不是没有代价的;因为元素是从许多线程中释放出来的,并发收集器通常无法保存遭遇顺序。(但是,通常您并不关心-在创建单词计数直方图时,您并不关心首先计算的是哪个"foo“实例。)
https://stackoverflow.com/questions/22350288
复制相似问题