Исключение Java HashMap ConcurrentModification, несмотря на использование синхронизированного блока

У меня есть хэш-карта, используемая одновременно в нескольких потоках. Чтобы сделать его потокобезопасным, я поместил его в синхронизированный блок:

private final Map<Long, DeviceConnection> mapConnections = new HashMap()<>;

...

synchronized (mapConnections) {
        List<Long> toClear = new ArrayList<>();
        for (Map.Entry<Long, AndroidSocketConnection> entry : mapConnections.entrySet()) {
            if (entry.getValue().isReadyToRemove())) {
                removed++;
                toClear.add(entry.getKey());
            }
        }
        for(Long toC : toClear) {
            mapConnections.remove(toC);
        }
    }

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

java.util.ConcurrentModificationException

в java.util.HashMap $ HashIterator.nextNode (HashMap.java:1442)

в java.util.HashMap $ EntryIterator.next (HashMap.java:1476)

в java.util.HashMap $ EntryIterator.next (HashMap.java:1474)

at myPackage.network.DeviceHandler.doClearing (DeviceHandler.java:51) // - › эта строка содержит заголовок цикла for показанного мной кода

в java.lang.Thread.run (Thread.java:748)


person julien-100000    schedule 31.03.2020    source источник
comment
Есть ли другой код, который работает с mapConnections?   -  person Joni    schedule 31.03.2020
comment
Да, конечно. Вот почему я использую синхронизированный блок. Я все время помещаю и удаляю элементы с этой карты в других потоках   -  person julien-100000    schedule 31.03.2020
comment
эти другие потоки также получают доступ через synchronized (mapConnections) блоки?   -  person Joni    schedule 31.03.2020
comment
Нет, но у меня есть ссылки на объекты в этом HashSet, в которых я изменяю атрибуты не в синхронизированных блоках, может ли это быть проблемой?   -  person julien-100000    schedule 31.03.2020
comment
Хорошо, это объясняет ConcurrentModificationException. Что касается работы с другими объектами без синхронизации, да, это определенно проблема. Это не вызовет ConcurrentModificationException, но у вас будут ошибки, которые трудно понять и трудно воспроизвести.   -  person Joni    schedule 31.03.2020


Ответы (1)


Это будет потокобезопасным только в том случае, если каждый доступ (как чтение, так и запись) к карте выполняется через блок synchronized.

ConcurrentModificationException будет выдан, когда карта будет повторяться во время ее модификации.

Я предлагаю вам перейти на _3 _, который является потокобезопасным и будет заменять его.

person ᴇʟᴇvᴀтᴇ    schedule 31.03.2020
comment
Звучит хорошо, но я также поместил все остальное в этом HashSet в синхронизированные блоки. - person julien-100000; 31.03.2020
comment
Но у меня есть ссылки на объекты в этом HashSet, в которых я изменяю атрибуты не в синхронизированных блоках, может ли это быть проблемой? - person julien-100000; 31.03.2020
comment
@ julien-100000 Влияют ли эти измененные атрибуты на результат метода hashCode? Это было бы очень плохо. - person Basil Bourque; 31.03.2020
comment
да, я почти уверен, что они это делают, потому что класс аннотирован Lomboks @Data - person julien-100000; 31.03.2020
comment
Если я использую ConcurrentHashMap, мне все равно нужно заботиться о том, чтобы хэш-код не был изменен, или я могу проигнорировать это тогда? @BasilBourque - person julien-100000; 31.03.2020
comment
Нет, это не сработает, если вы измените хэш-код ключа элемента. Вам необходимо сначала удалить запись, затем внести изменения и добавить обновленную версию. stackoverflow.com/questions/26959545/ Но ваш ключ Long, поэтому, вероятно, не будет затронуты этой проблемой. Неважно, измените ли вы хэш-код одного из значений, только ключ. - person ᴇʟᴇvᴀтᴇ; 31.03.2020
comment
Ах хорошо. Будет ли это работать, если я удалю свою собственную реализацию хэш-кода, а вы - версию по умолчанию из класса Object? - person julien-100000; 31.03.2020
comment
@ julien-100000 Какая реализация hashCode в объекте Java?. Результат: в зависимости от hashCode, например использования в качестве ключа в хэш-карте, вы должны реализовать equals & hashCode, используя стабильное значение в объекте, такое как идентификатор сотрудника для класса Employee или поле идентификатора продукта для Product класс. Стабильный означает, что значение не изменится во время работы вашего приложения или, по крайней мере, не изменится в течение срока использования хеш-функции, например, в качестве ключа на карте. - person Basil Bourque; 31.03.2020
comment
Хорошо, я понял. Спасибо вам обоим за вашу помощь! :) - person julien-100000; 31.03.2020