ConcurrentModificationException при использовании потока - PullRequest
0 голосов
/ 05 июля 2019

Я получаю

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 голосов
/ 05 июля 2019

Я не вижу, где текущий код изменяет набор. Таким образом, элемент объекта 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<>());

Или используйте обычную синхронизацию (для всех модификаций требуется блокировка, а также код, который вы разместили).

...