使用流时发生ConcurrentModificationException

时间:2019-07-05 13:12:49

标签: java hashmap java-stream concurrentmodification

我要

ConcurrentModificationException(java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1558)) 

,我怀疑我需要等到HashSet(nodeRefsWithTags)完全填充后再进行处理。还是有人有其他建议?

函数getTagRefs(sagerRef)被递归调用并填充nodeRefsWithTags

nodeRefsWithTags = new HashSet<>();
getTagRefs(sagerRef);

List<Tag> tags = nodeRefsWithTags.stream()
            .map(nodeRef -> ((List<NodeRef>)nodeService.getProperty(nodeRef, ContentModel.PROP_TAGS)))
            .filter(Objects::nonNull)
            .flatMap(Collection::stream)
            .map(taggingService::getTagName)
            .collect(Collectors.groupingBy(tagName -> tagName, Collectors.counting()))
            .entrySet().stream()
            .map(map -> new Tag(map.getKey(), map.getValue()))
            .collect(Collectors.toList());

1 个答案:

答案 0 :(得分:0)

我看不到当前代码在哪里修改了该集合。因此,对象成员nodeRefsWithTags似乎可以被其他线程访问,并且必须有另一个并发线程对其进行修改。在流式传输设置项目时,无法保证不会进行任何修改。有一些选项:

创建副本:

// At this point, you have to make sure nodeRefsWithTags is not modified by other threads.
Set<...> copy = new HashSet<>(nodeRefsWithTags);
// From now on it's ok to modify the original set
List<Tag> tags = copy.stream()...

使用ConcurrentHashMap

// For this option you have to make sure that no elements get removed from the map, else you
// might get an endless loop (!) which is very hard to find and may occur occationally only.
nodeRefsWithTags = Collections.newSetFromMap(new ConcurrentHashMap<>());

或使用普通同步(所有修改都需要锁以及您发布的代码)。