Разница между Hashtable и Collections.synchronizedMap(HashMap)
Насколько я знаю, java.util.Hashtable
синхронизирует каждый метод в java.util.Map
интерфейс, а Collections.synchronizedMap(hash_map)
возвращает объект-оболочку, содержащий синхронизированные методы делегирования вызовов фактическому hash_map
(исправьте меня, если я ошибаюсь).
У меня есть два вопроса:
-
Какая разница, чтобы синхронизировать каждый метод и иметь класс-оболочку? Каковы сценарии выбора одного над другим?
-
Что происходит, когда мы делаем Collections.synchronizedMap(hash_table)
? Будет ли это равным простому использованию обычного java.util.Hashtable
?
Ответы
Ответ 1
Вот ответы, которые я получил от небольшого (надеюсь, правильного) исследования:
-
Оба обеспечивают такую же степень синхронизации. Если вы должны были обернуть Hashtable
через Collections.synchronized, у вас будет такая же степень, но с другим избыточным уровнем синхронизации.
-
Основное отличие между Hashtable
и Collections.synchronizedMap(HashMap)
больше на уровне API. Поскольку Hashtable
является частью устаревшего кода Java, вы увидите, что API Hashtable
расширен для реализации интерфейса Map
, чтобы стать частью структуры коллекций Java. Это означает, что если вы должны были обернуть Hashtable
через Collections.synchronizedMap()
, API завернутого Hashtable
будет ограничен API Map
. Поэтому, если API Hashtable
включен в ваше определение поведения , то он явно изменен/ограничен.
Ответ 2
Еще одно отличие, которое я могу найти при реализации обоих классов, следующее:
• Класс Hashtable
имеет все свои методы синхронизации, т.е. блокировка выполняется на уровне метода, и, следовательно, можно сказать, что мьютекс всегда на объекте Hashtable
(this
).
• Метод Collections.synchronizedMap(Map)
возвращает экземпляр SynchronizedMap
, который является внутренним классом класса Collections
. Этот класс имеет все свои методы в блоке Synchronized
с мьютексом. Здесь разница в мьютексе. Внутренний класс SynchronizedMap
имеет два конструктора, один из которых принимает только Map
в качестве аргумента, а другой, который принимает в качестве аргумента Map
и Object
(mutex). По умолчанию, если использовать первый конструктор для передачи только a Map
, this
используется как мьютекс. Хотя разработчику разрешено передавать еще один объект мьютекса в качестве второго аргумента, по которому блокировка методов Map
будет только на этом Object
и, следовательно, менее ограничительна, чем Hashtable
.
• Следовательно, Hashtable
использует синхронизацию уровня метода, но Collections.synchronizedMap(Map)
обеспечивает гибкость блокировки разработчика при предоставленном мьютексе с блоком Synchronized
.
Ответ 3
Первый класс ассоциативной коллекции появится в классе Java библиотека была Hashtable, которая была частью JDK 1.0. Hashtable предоставлен простой в использовании, потокобезопасной, ассоциативной возможности карты, и это было конечно удобный. Тем не менее, безопасность потока достигла цены - Синхронизированы все методы Hashtable. В то время, без синхронизация имела измеримую стоимость исполнения. Преемник Hashtable, HashMap, который появился как часть Коллекций в JDK 1.2, направленной на обеспечение безопасности потоков путем предоставления несинхронизированный базовый класс и синхронизированную обертку, Collections.synchronizedMap. Разделение базовой функциональности от система Collections.synchronizedMap для обеспечения безопасности потоков позволила пользователям, которые нуждались в синхронизация, чтобы иметь его, но пользователям, которые не нуждались в нем, не было заплатить за это.
Простой подход к синхронизации, сделанный как Hashtable, так и synchronizedMap - синхронизация каждого метода на Hashtable или синхронизированный объект оболочки оболочки - имеет два основных недостатка. Это является препятствием для масштабируемости, поскольку только один поток может получить доступ хэш-таблицу за раз. В то же время этого недостаточно обеспечивают истинную безопасность резьбы, поскольку многие общие составные операции по-прежнему требуется дополнительная синхронизация. Хотя простые операции такие поскольку get() и put() могут безопасно дополняться без дополнительных синхронизации, существует несколько общих последовательностей операций, таких как итерация или put-if-absent, которые по-прежнему требуют внешних синхронизация, чтобы избежать расследований данных.
Следующая ссылка является источником и имеет более подробную информацию: Параллельные классы коллекций
Ответ 4
Разница не все на очевидном уровне API, и на уровне реализации есть много тонкостей. Например, Hashtable
не поддерживает HashMap
расширенный пересчет хэш-кодов поставляемых ключей, что уменьшает хеш-коллизии. С другой стороны, Hashtable#hashCode()
позволяет избежать бесконечной рекурсии для самореферентных хэш-таблиц, чтобы позволить "некоторым апплетам с 1,1-й эрой с самореферентными хеш-таблицами работать".
В целом, однако, нельзя рассчитывать на Hashtable
получение каких-либо дальнейших улучшений или уточнений за пределами базовой корректности и обратной совместимости. Это считается реликвией глубокого прошлого Java.
Ответ 5
С риском указания очевидного (или просто неправильного) не разница, что
Оболочки синхронизации добавляют автоматическую синхронизацию (безопасность потока) к произвольной коллекции
http://docs.oracle.com/javase/tutorial/collections/implementations/wrapper.html и продолжает говорить
Коллекция, созданная таким образом, каждый бит как поточно-безопасный, как обычно синхронизированный набор, такой как вектор.
Вам может понравиться эта тема для вопросов, касающихся HashMaps и concurrency - Hashmap concurrency issue (или вы, возможно, очень хорошо их знаете), Хорошим примером является:
Условия, которые вы описываете, не будут удовлетворены HashMap. поскольку процесс обновления карты не является атомарным, вы можете столкнуться с картой в недопустимом состоянии. Несколько записей могут оставить его в поврежденном состоянии государство. ConcurrentHashMap (1.5 или новее) делает то, что вы хотите.
fooobar.com/info/154975/...
Я предполагаю, что в терминах "когда я должен использовать это" я хотел бы использовать синхронизированную коллекцию, где требуется concurrency, иначе вы можете создавать больше работы для себя (см. ниже).
С точки зрения изменения поведения
Если используется явный итератор, следует вызвать метод итератора изнутри синхронизированного блока. Несоблюдение этого совета может приводят к недетерминированному поведению
Есть больше последствий использования синхронизации, предоставляемой на предоставляемой (Oracle) ссылке.