Почему ConcurrentHashMap предотвращает нулевые ключи и значения? - PullRequest
132 голосов
/ 30 марта 2009

JavaDoc ConcurrentHashMap говорит следующее:

Как и Hashtable, но в отличие от HashMap этот класс не допускает использование null в качестве ключа или значения.

Мой вопрос: почему?

2-й вопрос: почему Hashtable не допускает нулевое значение?

Я использовал много HashMaps для хранения данных. Но при переходе на ConcurrentHashMap у меня несколько раз возникали проблемы из-за исключений NullPointerExceptions.

Ответы [ 7 ]

205 голосов
/ 15 февраля 2012

От самого автора ConcurrentHashMap (Даг Ли) :

Основная причина, по которой пустые значения не разрешены в ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) - это те неоднозначности, которые может быть едва терпимым в не одновременных картах не может быть размещение. Основным является то, что если map.get(key) возвращает null, вы не может определить, соответствует ли ключ явно null против ключа нанесены на карту. На неконкурентной карте вы можете проверить это с помощью map.contains(key), но в одно и то же время карта могла измениться между вызовами.

40 голосов
/ 21 января 2011

Я полагаю, что это, по крайней мере частично, позволяет объединить containsKey и get в один вызов. Если карта может содержать нули, невозможно определить, возвращает ли get ноль, потому что не было ключа для этого значения, или просто потому, что значение было нулевым.

Почему это проблема? Потому что нет безопасного способа сделать это самостоятельно. Возьмите следующий код:

if (m.containsKey(k)) {
   return m.get(k);
} else {
   throw new KeyNotPresentException();
}

Поскольку m является одновременной картой, ключ k может быть удален между вызовами containsKey и get, в результате чего этот фрагмент кода возвращает ноль, которого никогда не было в таблице, вместо требуемого KeyNotPresentException.

Обычно вы решаете это путем синхронизации, но с параллельной картой это, конечно, не сработает. Следовательно, подпись для get должна была измениться, и единственный способ сделать это обратно-совместимым способом состоял в том, чтобы запретить пользователю вставлять нулевые значения в первую очередь, и продолжать использовать это в качестве заполнителя для «ключ не найден» .

4 голосов
/ 31 марта 2009

Джош Блох разработан HashMap; Даг Ли разработал ConcurrentHashMap. Я надеюсь, что это не клевета. На самом деле, я думаю, что проблема в том, что пустые значения часто требуют переноса, так что настоящий нулевой может быть неинициализированным Если клиентскому коду требуются значения NULL, тогда он может оплатить (по общему признанию, небольшую) стоимость упаковки NULL.

0 голосов
/ 08 января 2019

Я не думаю, что запрещение нулевого значения является правильным вариантом. Во многих случаях мы хотим поместить ключ с нулевым значением в текущую карту. Однако, используя ConcurrentHashMap, мы не можем этого сделать. Я полагаю, что будущая версия JDK может это поддерживать.

0 голосов
/ 30 марта 2009

Полагаю, что следующий фрагмент документации API дает хороший совет: «Этот класс полностью совместим с Hashtable в программах, которые полагаются на безопасность потоков, но не на детали синхронизации».

Возможно, они просто хотели сделать ConcurrentHashMap полностью совместимым / взаимозаменяемым для Hashtable. А так как Hashtable не допускает нулевые ключи и значения ..

0 голосов
/ 30 марта 2009

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

Редактировать: это не совсем то, почему в этом случае. Сначала я думал, что происходит что-то необычное с блокировкой на предмет одновременных обновлений или иным образом с помощью монитора объектов, чтобы определить, было ли что-то изменено, но после изучения исходного кода кажется, что я ошибался - они блокируются с помощью «сегмент», основанный на битовой маске хэша.

В этом случае я подозреваю, что они сделали это, чтобы скопировать Hashtable, и я подозреваю, что Hashtable сделал это, потому что в мире реляционных баз данных null! = Null, поэтому использование пустого значения в качестве ключа не имеет смысла.

0 голосов
/ 30 марта 2009

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

...