Подтвердить что ты не робот

Почему ConcurrentHashMap предотвращает нулевые ключи и значения?

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

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

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

Второй вопрос: почему Hashtable не разрешает null?

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

4b9b3361

Ответ 1

От автора ConcurrentHashMap себя (Doug Lea):

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

Ответ 2

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

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

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

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

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

Ответ 3

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

Ответ 4

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

Изменить: Это не совсем так, почему в этом случае. Первоначально я думал, что есть что-то фантастическое в том, что происходит с блокировкой от параллельных обновлений или иным образом с помощью монитора объектов, чтобы определить, было ли что-то изменено, но после изучения исходного кода кажется, что я ошибался - они блокируют использование "сегмента" на основе битмаски хеша.

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

Ответ 5

ConcurrentHashMap является потокобезопасным. Я считаю, что не разрешать нулевые ключи и значения были частью обеспечения безопасности потоков.

Ответ 6

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

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