Может ли получить, поместить и удалить elemetn в HashMap без итерации, вызывающей ConcurrentModificationException?

У меня есть статическая хэш-карта, совместно используемая несколькими потоками. Я вообще не повторяю карту, а просто использую get, put, remove. Это безопасно от ConcurrentModificationException ?

Метод выглядит так

private static Map<Long, Integer> TRACKER = new HashMap<Long,Integer>();
public static void track(Long tid, boolean b) {
        if (b) {
            if (TRACKER.containsKey(tid)) {
                TRACKER.put(tid, TRACKER.get(tid) + 1);
            } else {
                TRACKER.put(tid, 1);
            }
        } else {
            Integer n = TRACKER.get(tid);
            if (n != null) {
                n = n -1;
                if (n == 0) {
                    TRACKER.remove(tid);
                } else {
                    TRACKER.put(tid, n);
                }
            }
        }
    }

person Anthony C    schedule 06.09.2018    source источник
comment
В коде, который вы нам здесь показываете, нет ничего, что могло бы вызвать ConcurrentModificationException.   -  person khelwood    schedule 07.09.2018
comment
Ничто не вызовет исключения параллельной модификации... и это плохо, потому что происходит параллельная модификация и нарушается работа, но он не может это понять и выдает исключение, чтобы предупредить вас.   -  person Louis Wasserman    schedule 07.09.2018


Ответы (2)


Это безопасно от ConcurrentModificationException?

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

Однако, поскольку HashMap не является потокобезопасным классом, если вы используете его из нескольких потоков без надлежащей внешней внешней синхронизации, могут произойти плохие вещи. К ним относятся (в порядке возрастания вредности)

  1. Метод size() сообщает о неверном значении.
  2. Записи таинственно исчезают, временно или навсегда.
  3. Возможные NPE и другие непроверенные исключения.
  4. Возможные бесконечные циклы из-за неудачной последовательности операций нескольких потоков, создающих цикл в хеш-цепочке.

Код вашего примера небезопасен... но вы не получите "быстрый сбой" ConcurrentModificationException. Вместо этого вы, вероятно, получите необъяснимые ошибки в «случайные» моменты времени, которые трудно воспроизвести.

person Stephen C    schedule 07.09.2018

Если несколько потоков выполняют операции get, put и remove над HashMap без надлежащей синхронизации, могут возникнуть некоторые плохие вещи, такие как size(), сообщающие об отсутствующих/потерянных записях, неожиданных NPE... даже бесконечные циклы.

HashMap документация говорит:

Обратите внимание, что эта реализация не синхронизирована. Если несколько потоков одновременно обращаются к хэш-карте и по крайней мере один из потоков структурно изменяет карту, она должна быть синхронизирована извне. (Структурная модификация — это любая операция, которая добавляет или удаляет одно или несколько сопоставлений; простое изменение значения, связанного с ключом, который уже содержится в экземпляре, не является структурной модификацией.) ...

Спасибо, Стивен.

person Saketh Katari    schedule 07.09.2018
comment
Вы, вероятно, могли бы обновлять значения одновременно без синхронизации после прочтения этих документов, но я не могу представить механизмы, необходимые для выполнения проверок, необходимых для обновления значения, без случайного добавления нового значения. Это должно быть невероятно искусно. - person Ryan The Leach; 07.09.2018