并行流将项添加到同一个数组

问题描述 投票:3回答:1

我有一个对象数组,我将其转换为在每个对象上使用一个函数来修改它并将其添加到一个全新的对象数组中。

通过使用.parallel(),执行时间加快了2倍,但是当循环遍历新数组时,我得到了一些NullPointerExceptions。

我尝试调试几次没有任何成功。似乎这个问题只发生在运行时。我尝试实现一个同步函数来将新对象添加到列表中,但遗憾的是它不能正常工作。

谁能给我一个如何让这个工作的建议?提前致谢!

这是代码片段:

private static final Object sync = new Object();
private ArrayList<Object> newList = new ArrayList<Object>();      

private void addNewObject(Object newObject) {
        synchronized (sync) {
            newList.add(newObject);
        }
    }

private Object mutateObject(Object oldObject) {
    // Do something with the object here
    return mutatedObject;
}

public ArrayList<Object> createNewList(ArrayList<Object> oldList) {
    oldList.stream().parallel().forEach(object -> addNewObject(mutateObject(object)));
    return newList;
}
java java-stream
1个回答
3
投票

考虑将createNewList方法重构为以下内容:

public List<Object> createNewList(List<Object> oldList) {
    return oldList.parallelStream()
            .map(this::mutateObject)
            .collect(Collectors.toList());
}

如果你查看java.util.stream.Stream JavaDoc,你可以看到有一些终端操作,如forEachcollecttoArray等。在你的问题中,最好使用collect终端操作,因为它在内部处理同步,避免竞争条件情况,没有任何进一步的同步实现。

使用.map()Stream的中间操作)映射对象并将结果并行收集到最终列表可以解决此问题。

应删除addNewObject函数和sync对象,因为它不再使用。

© www.soinside.com 2019 - 2024. All rights reserved.