首页 > 解决方案 > 这个 IntStream 分区实现真的不是线程安全的吗?

问题描述

答案提供了对 IntStream 进行分区的实现:

IntStream intStream = IntStream.iterate(0, i -> i + 1).limit(1000000);

Predicate<Integer> p = x -> r.nextBoolean();
Map<Boolean, List<Integer>> groups = intStream.collect(() -> {
    Map<Boolean, List<Integer>> map = new HashMap<>();
    map.put(false, new ArrayList<>());
    map.put(true, new ArrayList<>());
    return map;
}, (map, x) -> {
    boolean partition = p.test(x);
    List<Integer> list = map.get(partition);
    list.add(x);
}, (map1, map2) -> {
    map1.get(false).addAll(map2.get(false));
    map1.get(true).addAll(map2.get(true));
});

System.out.println(groups.get(false).size());
System.out.println(groups.get(true).size());

但是它的编辑提到这个实现不是线程安全的。然而,据我所见,收集器HashMap<List<Integer>>为并行流中的每个线程创建了一个单独的线程。所以每个地图都被限制在一个线程中。分区功能也仅限于单个线程。合并函数合并来自多个线程的结果,但据我所知,流框架确保合并以线程安全的方式完成。所以我的问题是:这个解决方案真的不是线程安全的吗?

顺便说一句:无论如何,答案提供了一个更优雅的解决方案(Stream<Integer> stream = intStream.boxed();等),但我仍然想知道。

PS:我想将此问题添加为原始帖子的评论,但我什至没有添加评论的声誉......:|

标签: javamultithreadingconcurrencyjava-stream

解决方案


根据 Oracles 文档

与 reduce(int, IntBinaryOperator) 一样,collect 操作可以并行化,无需额外同步。

https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html#collect-java.util.function.Supplier-java.util.function.ObjIntConsumer-java.util。 function.BiConsumer-

所以看起来你的直觉是正确的,这是线程安全的。


推荐阅读