ConcurrentModificationException при вызове size () для подсписка - PullRequest
0 голосов
/ 25 июня 2018

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

Из-за архитектуры я сохраняю эти транзакции SQL 1000 на 1000 (я использую сообщениеQueue). Поэтому некоторые из них могут потерпеть неудачу, и я перенаправил их, чтобы повторить или отклонить. Чтобы повысить эффективность, я хочу улучшить старую систему, в которой при сбое 1000 вы сохраняете 1 на 1 для реализации дихотомии (если сбой не удастся, вы разбиваете список и пытаетесь снова), через рекурсивность . Я также отслеживаю атрибут моих объектов, благодаря другому списку (objectsNo) для дальнейших операций.

Однако я получаю ConcurrentModificationException , когда в моей первой рекурсивности, при вызове objectsList.size (). Как я могу избежать этого? Я также открыт, и был бы очень благодарен за любые решения, которые предоставили бы другой способ, кроме дихотомии, улучшить эффективность (и таким образом обойти мою проблему).

Подавлено: java.util.ConcurrentModificationException: null в java.util.ArrayList $ SubList.checkForComodification (ArrayList.java:1231) at java.util.ArrayList $ SubList.size (ArrayList.java:1040) в fr.company.project.esbname.mariadb.MariaDbDatabase.saveObjectWithDichotomie (MariaDbDatabase.java:398) в fr.company.project.esbname.mariadb.MariaDbDatabase.saveObjectWithDichotomie (MariaDbDatabase.java:404) в fr.company.project.esbname.mariadb.MariaDbDatabase.saveObject (MariaDbDatabase.java:350) at sun.reflect.GeneratedMethodAccessor324.invoke (неизвестный источник) at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) в java.lang.reflect.Method.invoke (Method.java:498) в org.apache.camel.component.bean.MethodInfo.invoke (MethodInfo.java:472) в org.apache.camel.component.bean.MethodInfo $ 1.doProceed (MethodInfo.java:291) в org.apache.camel.component.bean.MethodInfo $ 1.proceed (MethodInfo.java:264) в org.apache.camel.component.bean.BeanProcessor.process (BeanProcessor.java:178) в org.apache.camel.management.InstrumentationProcessor.process (InstrumentationProcessor.java:77) в org.apache.camel.processor.RedeliveryErrorHandler.process (RedeliveryErrorHandler.java:541) ... 22 общих кадра опущено

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

    private List<String> saveObjectWithDichotomie(List<Object> objects,
                                                            List<String> objectsNo,
                                                            Exchange exchange) throws JsonProcessingException {
    try {
        objectRepository.save(objects);

        return objectsNo;
    } catch (DataIntegrityViolationException e) {
        if (objects.size() == 1) {
            objectsNo.clear();
            errorProcessor.sendErrorToRejets(objects.get(0), exchange, e);

            return objectsNo;
        } else {
            List<Object> objectsFirstHalf = objects.subList(0, objects.size()/2);
            List<Object> objectsSecondHalf = objects.subList(objects.size()/2, objects.size());

            List<String> objectsNoFirstHalf = objectsNo.subList(0, objectsNo.size()/2);
            List<String> objectsNoSecondHalf = objectsNo.subList(objectsNo.size()/2, objectsNo.size());

            objectsNo.clear();

            objectsNo.addAll(
                    saveObjectWithDichotomie(objects, objectsNoFirstHalf, exchange)
            );
            objectsNo.addAll(
                    saveObjectWithDichotomie(objects, objectsNoSecondHalf, exchange)
            );

            return objectsNo;
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 25 июня 2018

Если вы читаете документацию sublist, ясно сказано:

Возвращенный список поддерживается этим списком, поэтому неструктурные изменения в возвращенном списке отражаются в этом списке,и наоборот.

Это и есть причина вашего исключения (для этого не нужно создавать несколько потоков).Таким образом, когда вы создаете новый список, создайте его с помощью:

List<Object> objectsFirstHalf = new ArrayList<>(objects.subList(0, objects.size()/2));
0 голосов
/ 25 июня 2018

Две вещи:

  1. ConcurrentModificationException не означает, что список был изменен другим потоком, но что-то пытается получить доступ к списку в ожидаемом состоянии, но за это время он был изменен.

  2. subList не создает фактический новый список, он создает представление в исходном списке. Это означает, что вы не можете изменить исходный список, не сделав полученный подсписок недействительным.

Итак,

objectsNo.clear();

это ваша проблема.

См. Этот MCVE:

public class Sublist {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(
                IntStream.range(0, 100).mapToObj(Integer::toString).collect(Collectors.toList()));

        List<String> sublist = list.subList(10, 20);

        // outputs "15"
        System.out.println(sublist.get(5));

        list.clear();

        // throws ConcurrentModificationException
        System.out.println(sublist.get(5));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...