Вопрос-ответ

What's the difference between ConcurrentHashMap and Collections.synchronizedMap(Map)?

В чем разница между ConcurrentHashMap и Collections.synchronizedMap (карта)?

У меня есть карта, которая должна быть изменена несколькими потоками одновременно.

Похоже, что в Java API существует три разные реализации синхронизированной карты:


  • Hashtable

  • Collections.synchronizedMap(Map)

  • ConcurrentHashMap

Насколько я понимаю, Hashtable это старая реализация (расширение устаревшего Dictionary класса), которая позже была адаптирована под Map интерфейс. Хотя он и синхронизирован, похоже, у него серьезные проблемы с масштабируемостью, и его не рекомендуется использовать в новых проектах.

Но как насчет двух других? В чем разница между картами, возвращаемыми Collections.synchronizedMap(Map) и ConcurrentHashMaps? Какая из них подходит для какой ситуации?

Переведено автоматически
Ответ 1

Для ваших нужд используйте ConcurrentHashMap. Это позволяет одновременно изменять карту из нескольких потоков без необходимости их блокировки. Collections.synchronizedMap(map) создает блокирующую карту, которая снижает производительность, хотя и обеспечивает согласованность (при правильном использовании).

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

Ответ 2
╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗
║ Property ║ HashMap ║ Hashtable ║ ConcurrentHashMap ║
╠═══════════════╬═══════════════════╬═══════════════════╩═════════════════════╣
║ Null ║ allowed ║ not allowed ║
║ values/keys ║ ║ ║
╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣
║ Thread-safety ║ ║ ║
║ features ║ no ║ yes ║
╠═══════════════╬═══════════════════╬═══════════════════╦═════════════════════╣
║ Lock ║ not ║ locks the whole ║ locks the portion ║
║ mechanism ║ applicable ║ map ║ ║
╠═══════════════╬═══════════════════╩═══════════════════╬═════════════════════╣
║ Iterator ║ fail-fast ║ weakly consistent ║
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

Относительно механизма блокировки:
Hashtable блокирует объект, в то время как ConcurrentHashMap блокирует только корзину.

Ответ 3

"Проблемы с масштабируемостью" для Hashtable присутствуют точно так же в Collections.synchronizedMap(Map) - они используют очень простую синхронизацию, что означает, что только один поток может получить доступ к карте одновременно.

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

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

Ответ 4

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

Также есть еще одно отличие в том, что ConcurrentHashMap не будет сохранен порядок элементов в переданной карте. Это аналогично HashMap при сохранении данных. Нет гарантии, что порядок элементов сохранен. While Collections.synchronizedMap() сохранит порядок элементов передаваемой карты. Например, если вы передадите TreeMap в ConcurrentHashMap, порядок элементов в ConcurrentHashMap может отличаться от порядка в TreeMap, но Collections.synchronizedMap() порядок сохранится.

Кроме того, ConcurrentHashMap можно гарантировать, что не будет ConcurrentModificationException выброса, пока один поток обновляет карту, а другой поток выполняет обход итератора, полученного из карты. Однако, Collections.synchronizedMap() это не гарантируется.

Есть один пост, который демонстрирует различия этих двух, а также ConcurrentSkipListMap.

java concurrency