Потокобезопасная карта с возможностью использования нулевого ключа

#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 метод для выполнения a remove при задании нулевого значения, после чего a get для этого ключа вернет null, и вы все равно получите гораздо более высокую производительность параллелизма.

4. Помните, что при использовании этого подхода синхронизация на возвращаемой карте обязательна всякий раз, когда вы выполняете итерацию по возвращаемой коллекции — см. javadoc на synchronizedMap .

Ответ №2:

Насколько я знаю, не существует ни простого способа создания, ConcurrentHashMap ни эквивалентного класса, поддерживающего null ключи или значения.

ConcurrentHashMap сильно отличается от Collections.synchronizedMap(new HashMap()) .

Прежде всего потому, что синхронизированная карта предотвратит одновременные обращения, даже если все обращения доступны только для чтения. ConcurrentHashMap не блокирует одновременный доступ для чтения и, в некоторых случаях, может даже принимать одновременные записи.

Но более важным является то, что Iterator значения, возвращаемые синхронизированной картой, подвержены выбрасыванию ConcurrentModificationException , если базовая карта модифицируется при использовании итератора. С другой стороны, ConcurrentHashMap итераторы гарантированно никогда не выдадут ошибку ConcurrentModificationException , даже если базовая карта была изменена при использовании итератора.