#java #synchronization #hashmap #concurrenthashmap
#java #синхронизация #hashmap #concurrenthashmap
Вопрос:
Мне нужен многопоточный объект Map для использования в кэшировании моего веб-сервера, и мне нужны null
ключи.
HashMap
позволяет мне иметь нулевые ключи, но ConcurrentHashMap
этого не делает. Я попытался создать синхронизированную версию HashMap
using Collections.synchronizedMap(new HashMap())
, но она также не принимает null
ключи.
Есть ли какая-либо альтернатива, которую я могу использовать, без необходимости реализовывать какой-либо способ переноса null
ключей?
Комментарии:
1. HashMap допускает только один нулевой ключ. Вы говорите о нулевых значениях?
2. JDK 1.6.0_23,
Collections.synchronizedMap(new HashMap())
отлично работает сnull
ключами и значениями.
Ответ №1:
Map
Возвращаемая Collections.synchronizedMap
поддерживает все функции Map
, которые вы ей предоставляете. Если вы даете ей HashMap
, она поддерживает null
ключ (а также null
значения, как вы сказали ) «…Мне нужно иметь «нулевые» значения ключа …» которые могут быть прочитаны любым способом). Что заставляет вас думать, что это не так?
Это работает так, как ожидалось, например:
import java.util.*;
public class MapTest
{
public static final void main(String[] args)
{
Map map;
try
{
map = Collections.synchronizedMap(new HashMap());
map.put("one", "a");
System.out.println("Size = " map.size());
map.put(null, "b");
System.out.println("Size = " map.size());
System.out.println("map.get(null) = " map.get(null));
}
catch (Exception ex)
{
System.out.println("Exception: " ex.getMessage());
ex.printStackTrace(System.out);
}
System.exit(0);
}
}
Вывод:
Размер = 1 Размер = 2 map.get(null) = b
Комментарии:
1. Верно, моя ошибка. Я по ошибке использовал ConcurrentHashMap для своего теста вместо обернутой хэш-карты. Спасибо.
2. @Iravanchi: СМЕХОТВОРНО! Легко сделать. Рад, что помогло,
3. Вряд ли это отличный выбор для кэша сервера. Кэш должен обладать очень высокой производительностью, т. е. незначительными затратами на блокировку. ConcurrentHashMap намного лучше подходит для этого. Если вы хотите разрешить нулевые значения, вы можете легко смоделировать это, расширив
ConcurrentHashMap
и переопределивput
метод для выполнения aremove
при задании нулевого значения, после чего aget
для этого ключа вернет null, и вы все равно получите гораздо более высокую производительность параллелизма.4. Помните, что при использовании этого подхода синхронизация на возвращаемой карте обязательна всякий раз, когда вы выполняете итерацию по возвращаемой коллекции — см. javadoc на
synchronizedMap
.
Ответ №2:
Насколько я знаю, не существует ни простого способа создания, ConcurrentHashMap
ни эквивалентного класса, поддерживающего null
ключи или значения.
ConcurrentHashMap
сильно отличается от Collections.synchronizedMap(new HashMap())
.
Прежде всего потому, что синхронизированная карта предотвратит одновременные обращения, даже если все обращения доступны только для чтения. ConcurrentHashMap
не блокирует одновременный доступ для чтения и, в некоторых случаях, может даже принимать одновременные записи.
Но более важным является то, что Iterator
значения, возвращаемые синхронизированной картой, подвержены выбрасыванию ConcurrentModificationException
, если базовая карта модифицируется при использовании итератора. С другой стороны, ConcurrentHashMap
итераторы гарантированно никогда не выдадут ошибку ConcurrentModificationException
, даже если базовая карта была изменена при использовании итератора.