Java Concurrent коллекция для нескольких записей и частых чтений
Я хочу использовать карту значения ключа на основе компаратора. Это будет чтение и редкая операция записи (один раз в 3 месяца через планировщик). Первоначальная загрузка коллекции будет выполнена при запуске приложения. Также обратите внимание, что запись будет:
- Добавить одну запись на карту
- Не будет изменять любую существующую запись на карте.
Будет ли ConcurrentSkipListMap хорошим кандидатом для этого. Является ли операция get на этом доступе к нескольким потокам одновременно? Я ищу одновременное чтение без блокировки, но атомарную запись.
3 ответа
ConcurrentHashMap
это именно то, что вы ищете. Из Javadoc:
Операции извлечения (включая get) обычно не блокируются, поэтому могут перекрываться с операциями обновления (включая put и remove). Извлечения отражают результаты самых последних завершенных операций обновления, проводимых с момента их появления. (Более формально, операция обновления для данного ключа имеет отношение "происходит до" с любым (не нулевым) поиском для этого ключа, сообщающего об обновленном значении.)
Это звучит так, как будто это удовлетворяет вашему требованию для "одновременного не блокирующего чтения, а атомарного чтения"
Так как вы делаете так мало записей, вы можете указать высокий loadFactor и соответствующий initialSize при создании ConcurrentHashMap, что предотвратит изменение размера таблицы при заполнении карты, хотя в лучшем случае это незначительное преимущество. (Вы также можете установить для параметра concurrencyLevel значение 1, хотя Javadoc в Java 8, похоже, подразумевает, что он больше не используется в качестве подсказки для определения размера.)
Если вам абсолютно необходимо иметь SortedMap
или же NavigableMap
, затем ConcurrentSkipListMap
это готовый путь. Но я бы дважды проверил, что вам действительно нужны функциональные возможности, предоставляемые этими интерфейсами (получение первого / последнего ключа, вложенных карт, поиск соседних записей и т. Д.), Прежде чем их использовать. Вы заплатите высокую цену (log n или постоянное время для большинства операций).
Если вы хотите попробовать сторонний код, вы можете рассмотреть вариант карт с копированием при записи, которые идеально подходят для редких записей. Вот тот, который появился через Google:
https://bitbucket.org/atlassian/atlassian-util-concurrent/wiki/CopyOnWrite%20Maps
Никогда не пробовал сам так будьте бдительны.
Поскольку вы ищете параллельные операции, у вас есть в основном 3 конкурента. Hashtable, ConcurrentHashMap, ConcurrentSkipListMap (или Collections.synchronizedMap (), но это неэффективно).
- Из этих 3 последние 2 больше подходят для одновременной работы, поскольку они просто блокируют часть карты, а не блокируют всю карту, как Hashtable.
- Из последних 2 SkipListMap использует структуру данных списка пропусков, которая обеспечивает среднюю производительность O (log n) для быстрого поиска и различных операций.
- Он также предлагает ряд операций, которые ConcurrentHashMap не может выполнить, например, floorEntry/Key(), floorEntry / Key () и т. Д. Он также поддерживает порядок сортировки, который в противном случае должен был бы быть рассчитан.
Таким образом, если бы вы запросили только более быстрый поиск, я бы предложил ConcurrentHashMap, но, поскольку вы также упомянули "редкие операции записи" и "требуемый порядок сортировки", я думаю, что ConcurrentSkipListMap выиграет гонку.