Я думаю, что вы делаете, вполне разумно. Вы только используете структуру, чтобы получить чередование блокировок на ключе, чтобы гарантировать, что доступ к тому же самому ключу конфликтует. Не беспокойтесь, что вам не нужно сопоставление значений для каждого ключа. ConcurrentHashMap
и friends - единственная структура в библиотеках Java + Guava, которая предлагает вам чинить блокировки.
Это вызывает некоторые незначительные накладные расходы времени выполнения, плюс размер хеш-таблицы, который вам не нужен (который может даже возрасти, если доступ к одному и тому же сегменту накапливается и удаляется () не поддерживается).
Если вы хотите сделать его как можно более дешевым, вы можете самостоятельно написать код для снятия блокировки. В основном это Object[]
(или Array[AnyRef]
:)) из N блокировок (N = уровень параллелизма), и вы просто отображаете хэш ключа поиска в этот массив и блокируете. Еще одним преимуществом этого является то, что вам действительно не нужно делать трюки с хеш-кодом, которые требуются CHM, потому что последний должен разделить хеш-код на одну часть, чтобы выбрать блокировку, а другую - для нужд хеш-таблицы, но вы можете используйте все это только для выбора блокировки.
edit : зарисовка моего комментария ниже:
val concurrencyLevel = 16
val locks = (for (i <- 0 to concurrencyLevel) yield new AnyRef).toArray
def access(key: K): V = {
val lock = locks(key.hashCode % locks.size)
lock synchronized {
val valueFromCache = cache.lookup(key)
valueFromCache match {
case Some(v) => return v
case None =>
val valueFromBackend = backendServer.lookup(key)
cache.put(key, valueFromBackend)
return valueFromBackend
}
}
}
(Кстати, нужен ли вызов toArray
? Или возвращенный IndexSeq уже быстро доступен по индексу?)