Подтвердить что ты не робот

Hashmap concurrency вопрос

У меня есть Hashmap, что по причинам скорости я бы не требовал блокировки. Будет ли обновление и доступ к нему в то же время вызывать какие-либо проблемы, если я не против устаревших данных?

Мои обращения - это получение, а не повторение через него, а удаление - часть обновлений.

4b9b3361

Ответ 1

Да, это вызовет серьезные проблемы. Одним из примеров является то, что может произойти при добавлении значения в хэш-карту: это может привести к переименованию таблицы, и если это произойдет, когда другой поток выполняет итерацию по списку столкновений (хеш-таблицу "bucket" ), этот поток может ошибочно не найти ключ, который существует на карте. HashMap явно небезопасен для одновременного использования.

Используйте ConcurrentHashMap вместо этого.

Ответ 2

Важность синхронизации или использования ConcurrentHashMap не может быть занижена.

Я был под дезориентированным впечатлением, пока пару лет назад не смог уйти, только синхронизируя операции put и remove на HashMap. Это, конечно, очень опасно и фактически приводит к бесконечному циклу в HashMap.get() для некоторых (ранних 1.5, я думаю) jdk's.

Что я сделал пару лет назад (и действительно не нужно делать):

public MyCache {
    private Map<String,Object> map = new HashMap<String,Object>();

    public synchronzied put(String key, Object value){
        map.put(key,value);
    }

    public Object get(String key){
        // can cause in an infinite loop in some JDKs!!
        return map.get(key);
    }
}

EDIT: я бы добавил пример того, что делать не (см. выше)

Ответ 3

В случае сомнений проверьте класс Javadocs:

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

Map m = Collections.synchronizedMap(new HashMap(...));

(акцент не мой)

Итак, основываясь на том факте, что вы сказали, что ваши потоки будут удалять сопоставления с Картой, ответ заключается в том, что да это определенно вызовет проблему, и да, это определенно небезопасно.

Ответ 5

Условия, которые вы описываете, не будут удовлетворены HashMap. Поскольку процесс обновления карты не является атомарным, вы можете столкнуться с картой в недопустимом состоянии. Несколько записей могут оставить его в поврежденном состоянии. ConcurrentHashMap (1.5 или новее) делает то, что вы хотите.

Ответ 6

Если "в то же время" вы имеете в виду из нескольких потоков, тогда да, вам нужно заблокировать доступ к нему (или использовать ConcurrentHashMap или подобное, что делает блокировку для вас).

Ответ 7

Нет, проблем не будет, если вы выполните следующее:

  • Поместите свои данные в HashMap при первой загрузке одного потока до того, как произойдет многопоточность. Это связано с тем, что процесс добавления данных изменяет modcount и отличается при первом добавлении (возвращается нуль) и заменяет данные (старые данные будут возвращены, но modcount не будет изменен). Modcount - это то, что делает итераторы неудачными. Однако, если вы используете get, ничего не будет повторено, так что это нормально.

  • Иметь одинаковые ключи во всем приложении. После запуска приложения и загрузки его данных никакие другие ключи не могут быть назначены этой карте. Таким образом, get получит либо устаревшие данные, либо данные, которые были вставлены свежим - проблем не возникнет.

Ответ 8

Как и другие упоминаемые, используйте ConcurrentHashMap или синхронизируйте карту при ее обновлении.

Ответ 9

Я читаю здесь или где-то еще, нет, у вас нет доступа из нескольких потоков, но никто не говорит, что действительно происходит.

Итак, я видел сегодня (то, почему я нахожусь на этом - старом - вопрос) в приложении, запущенном в производстве с марта: 2, помещенный в тот же HashSet (затем HashMap), вызывает перегрузку ЦП (около 100%), и увеличение памяти на 3 ГБ, затем вниз по GC. Мы должны перезапустить приложение.