Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ArrayList上使用的流API reduce未同步_Java_Java Stream_Reduce - Fatal编程技术网

Java ArrayList上使用的流API reduce未同步

Java ArrayList上使用的流API reduce未同步,java,java-stream,reduce,Java,Java Stream,Reduce,我正在使用StreamAPI reduce测试字符串数组列表 for (int i = 0; i < 100; i++) { Stream<String> s1 = Stream.of("aa", "ab", "c", "ad"); Predicate<String> predicate = t -> t.contains("a"); List<String> strings2 = new

我正在使用StreamAPI reduce测试字符串数组列表

for (int i = 0; i < 100; i++)
    {
        Stream<String> s1 = Stream.of("aa", "ab", "c", "ad");
        Predicate<String> predicate = t -> t.contains("a");

        List<String> strings2 = new ArrayList<>();
        s1.parallel().reduce(new ArrayList<String>(),
                new BiFunction<ArrayList<String>, String, ArrayList<String>>()
                {
                    @Override
                    public ArrayList<String> apply(ArrayList<String> strings, String s)
                    {
                        if (predicate.test(s))
                        {
                            strings.add(s);
                        }

                        return strings;
                    }
                }, new BinaryOperator<ArrayList<String>>()
                {
                    @Override
                    public ArrayList<String> apply(ArrayList<String> strings,
                            ArrayList<String> strings2)
                    {
                        return strings;
                    }
                }).stream().forEach( //
                        e -> {
                            strings2.add(e);
                        });

        if (strings2.contains(null))
        {
            System.out.println(strings2);
        }
    }
}
所以我的问题是:
我使用reduce的方式是不正确的,还是应该做一些额外的事情来确保sych?

看起来
过滤器
更适合解决这个问题。但是,如果要使用reduce,尤其是在并行使用reduce时,则不能修改累加器对象(本例中的列表)

从:

每次处理元素时,累加器函数也会返回一个新值

当我运行您的代码时,我得到了两份包含
null
的列表打印件,后面是
ArrayIndexOutOfBoundsException
。可能的原因是两个线程试图同时将元素添加到同一个列表中。异常发生在列表变长之后,但在添加元素之前,因此出现了
null
(即空)插槽

ArrayList strings2=
s1.parallel()
.reduce(新的ArrayList(),
(列表,el)->{
如果(el.包含(“a”)){
添加的ArrayList=新的ArrayList(列表);
添加。添加(el);
增加了退货;
}
退货清单;
}, 
(列表1、列表2)->{
合并的ArrayList=新的ArrayList(列表1);
合并。添加全部(列表2);
返回合并;
});
您不必添加到列表中,而必须复制它,添加到该副本并返回副本。这样,每个线程可以在输入的不同部分上工作,而不会干扰其他部分


此外,您不能在组合器中丢弃部分结果,否则您将得到不完整的结果。您必须合并列表,而不是简单地返回其中一个。

s1.parallel()
创建并行流,如
聚合操作和并行流中所述,如果您在操作集合时不修改集合,则可以使用非线程安全集合实现并行
累加器和组合器函数不应修改
字符串
列表。使用串行流(
s1.reduce(…
)可能是一种解决方案,可以保证“同步”您读过的任何博客,停止阅读它们。
List strings2=Stream.of(“aa”、“ab”、“c”、“ad”).parallel().filter(t->t.contains(“a”).collect(Collectors.toList())
是这样做的正确方法。你正在做的事情是不完整的,非常复杂的。@霍尔格,首先,感谢你在这里所做的评论。我的问题不是“最好在这里使用
过滤器
,或者在这里使用
减少
,但我确实想学习如何使用
减少
换句话说,是线程安全的方式。我认为
reduce
函数是线程安全的,但是它在这里显示的内容已经证明我是错的,所以我想知道这里是否有线程安全的方式来
reduce
reduce
是线程安全的,如果使用正确的话。事实上,每个线程安全的构造只有在使用时才是安全的d正确。但是当一个博客说“在这种情况下可以使用reduce”时,这是非常错误的。链接教程还提到了创建许多新累加器列表的性能损失。对于这种情况,他们建议使用
Stream.collect
,而不是执行“可变”的减少,即,实际上允许您修改累加器对象。在问题的代码中,合并器没有丢弃结果,因为它在两个参数中都收到了相同的列表。但是,这并不是一个正确的解决方案……您提到的“两个线程试图同时将元素添加到同一列表中”这一点,我完全同意这一点,我能解决这一问题的简单原因是使用
CopyOnWriteArrayList
而不是
ArrayList
。好吧……我想得到的要点是,我想了解更多关于如何正确使用
reduce
的知识。对于
组合器
,我相信不使用
的列表是正确的第二个参数的列表与第一个参数的列表相同。@Robinson要理解
reduce
,您必须掌握值的概念。值是不能修改的,一种类型只能有不同的值。您可以计算一个值(或多个值)当您想到不可变列表时,您可以将列表连接到新列表,空列表是连接的标识值,但是当您将指定为第一个参数的
列表
修改为
reduce
时,它不再是标识值,并且整个操作在语义上是错误的,无论是什么原因d安全。
strings2.contains(null)
ArrayList<String> strings2 = 
    s1.parallel()
      .reduce(new ArrayList<String>(), 
              (list, el) -> {
                if (el.contains("a")) {
                    ArrayList<String> added = new ArrayList<>(list);
                    added.add(el);
                    return added;
                }
                return list;
              }, 
              (list1, list2) -> {
                ArrayList<String> merged = new ArrayList<>(list1);
                merged.addAll(list2);
                    return merged;
              });