Java для каждой лямбды бросает concurrentModificationException - PullRequest
0 голосов
/ 18 мая 2018

В чем может быть причина того, что метод ниже выдает ConcurrentModificationException?

static Set<String> setOfAllocAccountsIn(final @NotNull Execution execution) {
        final Set<String> allocAccounts = new HashSet<>();
        execution.legs().forEach(leg -> leg.allocs().forEach(alloc -> {
            if (alloc.account() != null) {
                allocAccounts.add(alloc.account());
            }
        }));
        return allocAccounts;
    }

Трассировка стека:

"java.util.ConcurrentModificationException:
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1382)
    at com.client.stp.util.DealsBuilderUtil.setOfAllocAccountsIn(DealsBuilderUtil.java:146)
    at com.client.stp.builder.GridDealsObjectBuilder.build(GridDealsObjectBuilder.java:47)
    at com.client.stp.processor.DealToPDXMLTransformer.transform(DealToPDXMLTransformer.java:29)
    at com.client.stp.processor.WorkPartitionerEngine.lambda$onEventSubmit$0(WorkPartitionerEngine.java:40)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:514)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.base/java.lang.Thread.run(Thread.java:844)

При простом for-loop он работает нормально.Метод вызывается несколькими потоками с собственной копией объекта выполнения.

Решение, которое работало с простым циклом for:

 static Set<String> setOfAllocAccountsIn(final @NotNull Execution execution) {
        final Set<String> allocAccounts = new HashSet<>();
        for (final ExecutionLeg executionLeg : execution.legs()) {
            for (final ExecutionAlloc executionAlloc : executionLeg.allocs()) {
                if (executionAlloc.account() != null) {
                    allocAccounts.add(executionAlloc.account());
                }
            }
        }
        return allocAccounts;
    }

Я чувствую, что оно как-то связано со статическим методом иего локальная переменная доступна для нескольких потоков, но согласно теории это будет локальная переменная потока и не будет использоваться совместно.Дайте мне время, чтобы изложить простой пример.

1 Ответ

0 голосов
/ 18 мая 2018

Ваша логика может быть такой:

return execution.legs().stream()
            .flatMap(leg -> leg.allocs().stream())
            .map(executionAlloc -> executionAlloc.account())
            .filter(Objects::nonNull)
            .collect(Collectors.toSet());
  • Вы используете forEach внутри forEach (Здесь я заменяю его на flatMap)
  • , затем выпроверьте для каждого элемента, является ли alloc.account() нулевым или нет (я заменяю его на filter)
  • , тогда, если условие корректно, вы добавляете его в набор (я заменяю его на collect)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...