Что эффективнее в Java: Hashtable или ConcurrentHashMap?

Ответ

ConcurrentHashMap значительно эффективнее Hashtable в многопоточных сценариях.

Сравнение механизмов синхронизации:

Критерий Hashtable ConcurrentHashMap
Уровень блокировки Блокирует весь объект (монитор) на время любой операции (put, get). Использует сегментированные блокировки (до Java 8) или операции CAS на отдельных узлах (Java 8+).
Параллелизм Нулевой — только один поток может работать с таблицей одновременно. Высокий — множество потоков могут читать и модифицировать разные сегменты/узлы одновременно.
Производительность Низкая из-за глобальной блокировки. Высокая, особенно при большом количестве потоков и операций записи.
Null-значения Не разрешает null ни для ключей, ни для значений. Также не разрешает null.
Статус Устаревший (legacy) класс. Современная, рекомендуемая реализация.

Пример использования ConcurrentHashMap:

import java.util.concurrent.ConcurrentHashMap;

ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
// Потокобезопасные операции без блокировки всей таблицы
concurrentMap.put("key1", 100);
Integer value = concurrentMap.get("key1");

Вывод: Hashtable следует считать устаревшим. Для многопоточных ассоциативных массивов всегда выбирайте ConcurrentHashMap. Для однопоточного использования подойдет HashMap.

Ответ 18+ 🔞

А, слушай, смотри, вот тебе наглядная разница, чтобы в голове сразу всё встало на свои места. Есть два персонажа: старый дед Hashtable и современный качок ConcurrentHashMap. И один из них — просто пиздец какой тормознутый.

Hashtable — это как общага на ремонте, где один-единственный, блядь, ключ от всех дверей. Хочешь зайти в свою комнату — бери ключ, но пока ты там, весь остальной дом стоит и ждёт, ёпта. Любая операция, даже просто посмотреть, что в холодильнике (get), блокирует весь объект целиком. Параллелизм? Ноль, хуй, пустота. Один поток работает, остальные — в очереди, как лохи.

А теперь ConcurrentHashMap — это уже не общага, а современный бизнес-центр с кучей отдельных офисов. В Java 7 и раньше он делил карту на сегменты и блокировал только тот, с которым работал поток. Остальные-то свободны! А с Java 8 там вообще красота — на узлах используют CAS-операции (Compare-And-Swap), это такая хитрая хуйня без тяжёлых блокировок. Короче, пока один поток ебёт один узел, другой спокойно может работать с соседним. Производительность — просто овердохуища, особенно когда потоков много.

Критерий Hashtable (дед) ConcurrentHashMap (качок)
Уровень блокировки Весь объект, глобальный лок. Сегменты или отдельные узлы (умная хуйня).
Параллелизм Нулевой, один в поле воин. Высокий, много потоков могут пахать одновременно.
Производительность Низкая, тормоз как отбойный молоток. Высокая, летает.
Null-значения Нельзя ни ключ, ни значение — сразу исключение. Тоже нельзя, и правильно, нахуй они сдались.
Статус Устаревший легаси-класс, музейный экспонат. Современная, основная реализация для многопоточки.

Вот как этим качком пользоваться, элементарно:

import java.util.concurrent.ConcurrentHashMap;

ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
// Кладёшь и берёшь без страха, что всё наебнётся
concurrentMap.put("key1", 100);
Integer value = concurrentMap.get("key1");

Итог, блядь: Hashtable — это прошлый век, пыльный и медленный. Для многопоточных задач бери только ConcurrentHashMap. А если поток один, то и обычный HashMap с головой, зачем сложности. Всё, вопрос закрыт.