Разница между Hashtable и Collections.synchronizedMap (HashMap) - PullRequest
45 голосов
/ 16 января 2012

Насколько я знаю, java.util.Hashtable синхронизирует каждый метод в интерфейсе java.util.Map, а Collections.synchronizedMap(hash_map) возвращает объект-оболочку содержащий синхронизированные методы, делегирующие вызовы фактическим hash_map (поправьте меня, если я ошибаюсь).

У меня два вопроса:

  1. Какая разница, чтобы синхронизировать каждый метод и иметь класс-оболочку? Каковы сценарии выбора одного из других?

  2. Что происходит, когда мы делаем Collections.synchronizedMap(hash_table)? Будет ли это равносильно использованию обычного java.util.Hashtable?

Ответы [ 6 ]

60 голосов
/ 28 февраля 2014

Еще одно отличие, которое я могу найти при реализации обоих классов, заключается в следующем:

• Класс Hashtable синхронизирует все свои методы, т. Е. Блокировка выполняется на уровне метода, и, следовательно, можно сказать, что мьютекс всегда в объекте Hashtable (this) уровень.

• Метод Collections.synchronizedMap(Map) возвращает экземпляр SynchronizedMap, который является внутренним классом для класса Collections. Этот класс имеет все свои методы в блоке Synchronized с мьютексом. Разница здесь в мьютексе. Внутренний класс SynchronizedMap имеет два конструктора, один из которых принимает в качестве аргумента только Map, а другой - в качестве аргумента Map и Object (мьютекс). По умолчанию, если используется первый конструктор с передачей только Map, this используется в качестве мьютекса. Однако разработчику разрешено передавать другой объект мьютекса в качестве второго аргумента, с помощью которого блокировка методов Map будет только для этого Object и, следовательно, менее ограничительной, чем Hashtable.

• Следовательно, Hashtable использует синхронизацию на уровне метода, но Collections.synchronizedMap(Map) предоставляет гибкость для блокировки разработчика на предоставленном мьютексе с блоком Synchronized.

15 голосов
/ 16 января 2012

Вот ответы, которые я получил от небольшого (надеюсь, правильного) исследования:

  1. Оба обеспечивают одинаковую степень синхронизации. Если бы вы обернули Hashtable через Collections.synchronized, у вас была бы та же степень, но с другим избыточным уровнем синхронизации.

  2. Основное различие между Hashtable и Collections.synchronizedMap(HashMap) существует больше на уровне API. Поскольку Hashtable является частью унаследованного кода Java, вы увидите, что API Hashtable улучшен для реализации интерфейса Map, чтобы стать частью инфраструктуры коллекций Java. Это означает, что если вы обернетесь от Hashtable до Collections.synchronizedMap(), API обернутого Hashtable станет ограниченным Map API. Так что, если API Hashtable включен в ваше определение поведения , то он явно изменен / ограничен.

4 голосов
/ 16 января 2012

Первым ассоциативным классом коллекции, появившимся в библиотеке классов Java, был Hashtable, который был частью JDK 1.0.Hashtable предоставил простую в использовании, поточно-ориентированную ассоциативную карту, и это было, безусловно, удобно.Тем не менее, безопасность потоков достигла своей цены - все методы Hashtable были синхронизированы.В то время неконтролируемая синхронизация имела ощутимые затраты производительности.Преемник Hashtable, HashMap, который появился как часть инфраструктуры Collections в JDK 1.2, решал проблему безопасности потоков, предоставляя несинхронизированный базовый класс и синхронизированную оболочку Collections.synchronizedMap.Отделение базовой функциональности от Thread-Safety Collections.synchronizedMap позволяет пользователям, которым нужна синхронизация, иметь ее, но пользователям, которым она не нужна, не нужно платить за нее.

Простой подход к синхронизациикак для Hashtable, так и для synchronizedMap - синхронизация каждого метода в Hashtable или синхронизированном объекте-оболочке Map - имеет два принципиальных недостатка.Это препятствует масштабируемости, потому что только один поток может одновременно обращаться к хеш-таблице.В то же время этого недостаточно для обеспечения истинной безопасности потоков, поскольку многие общие составные операции все еще требуют дополнительной синхронизации.В то время как простые операции, такие как get () и put (), могут безопасно завершаться без дополнительной синхронизации, есть несколько общих последовательностей операций, таких как итерация или put-if-отсутствующий, которые все еще требуют внешней синхронизации, чтобы избежать скачек данных.

Следующая ссылка является источником и содержит больше информации: Классы одновременных коллекций

3 голосов
/ 12 декабря 2012

Разница не все на очевидном уровне API, и на уровне реализации есть много тонкостей. Например, Hashtable не поддерживает расширенный HashMap расширенный пересчет хеш-кодов предоставленных ключей, который уменьшает коллизии хеш-функций. С другой стороны, Hashtable#hashCode() позволяет избежать бесконечной рекурсии для самореферентных хеш-таблиц, что позволяет «работать некоторым апплетам 1.1-эры с самообращающимися хеш-таблицами».

В общем, однако, не стоит рассчитывать на Hashtable получение каких-либо дальнейших улучшений или уточнений, кроме базовой корректности и обратной совместимости. Это считается пережитком глубокого Java-прошлого.

2 голосов
/ 14 апреля 2018

Еще одно отличие, на которое следует обратить внимание, заключается в том, что HashTable не допускает нулевые ключи или значения, тогда как HashMap допускает один нулевой ключ и любое количество нулевых значений. Поскольку synchronizedMap является оболочкой для HashMap, его поведение по отношению к нулевым ключам и значениям такое же, как и для HashMap.

1 голос
/ 16 января 2012

Риск указания очевидного (или просто ошибочного) разницы не в том, что

Оболочки синхронизации добавляют автоматическую синхронизацию (потокобезопасность) к произвольной коллекции

http://docs.oracle.com/javase/tutorial/collections/implementations/wrapper.html и продолжает говорить

Коллекция, созданная таким образом, столь же поточно-ориентированная, как и нормально синхронизированная коллекция, такая как Vector.

Возможно, вы захотите посмотреть эту ветку, чтобы узнать о проблемах, связанных с HashMaps и параллелизмом - Проблема параллелизма Hashmap (или вы, возможно, уже очень хорошо о них знаете).Хороший пример:

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

https://stackoverflow.com/a/1003071/201648

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

С точки зрения изменения поведения

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

Существуют и другие последствия использования синхронизации, указанной в ссылке (Oracle).

...