powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Java [игнор отключен] [закрыт для гостей] / Cache на основе ConcurrentHashMap. Метод computeIfAbsent блокируется.
2 сообщений из 2, страница 1 из 1
Cache на основе ConcurrentHashMap. Метод computeIfAbsent блокируется.
    #39897266
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Коллеги, такое дело.

В спринге есть аспект @Cacheable, который кеширует результат высичления метода. Есть еще JSR107 с аннотацией @CacheResult. Суть одна и та же. Для своего проекта я сделал нечто похожее, аспекты на основе CDI (мне для своих нужд было удобнее свое написать), выглядит так:

Код: java
1.
2.
3.
4.
@SessionCache(tags = Tag.DOCUMENT_TYPES)
public DocumentTypes getDocumentTypes() {
   // чтение документных типов из базе - тяжелая операция, поэтому кешируем
}


В примере вверху используется кеш SessionScoped, т.е. кеш будет жить только пока http сессия клиента жива и проинвалидируется, когда сессия умрет. Помимо этого есть еще @RequestCache и @ApplicationCache. Второе условие, когда кеш может быть сброшен, можно указать в тегах. В примере наверху, это tags = Tag.DOCUMENT_TYPES. Т.е. если аспект обнаруживает, что DOCUMENT_TYPES поменялись, то сбрасывает кеш.

Такая работа меня полностью устраивает. Внутри использую ConcurrentHashMap.
Так как значения в кеше еще может не быть, и несколько потоков одновременно вызовят этот метод, я не хочу, чтобы метод выполнился несколько раз, поэтому я использую метод ConcurrentHaspMap#computeIfAbsent, который гарантирует нам, что функция вычисляющая значение, будет выполнена один раз. Это аналог того, что дает спринг в аннотации @Cacheable(sync=true)
Так вот оказалось, что метод ConcurrentHaspMap#computeIfAbsent может блокирнуться при таком сценарии:
Код: java
1.
map.computeIfAbsent("key", s -> map.computeIfAbsent("key2", s1 -> "value"));


Т.е. когда мы рекурсивно вызываем computeIfAbsent внутри функции вычисления значения. Про это, в принципе, написано в документации к ConcurrentHashMap:
Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map.
Такая ситуация возможна например если мы имеем два метода оба аннотированные @SessionCache, и если один вызывает второй:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
@SessionCache
public MimeType getMimeType(String type) {
   // вызываем другой метод с аннотацией @SessionCache
   mimeTypesBean.getAllMimeTypes();
   // фильтруем mime types и возвращаем тот что совпадает по type
}
@SessionCache
public List<MimeType> getAllMimeTypes() {
   return //...
}



Я начал разбираться, что там в EHCache, ведь для on heap кеша он использует тот же ConcurrentHashMap
И у него такой проблемы не возникло! И я обнаружил в исходниках, что они используют не computeIfAbsent, а просто compute. И именно этот метод не блокируется при рекурсивном вызове (по крайней мере на моих данных). Но к этому методу тоже написано в документации
Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map.
Как-то стремно получить такую блокировку на боевом было бы. Так что я наверное запрещу вызов метода с аспектом кеширования, если в цепочке вызовов уже такой имелся. А вы что думаете?
...
Рейтинг: 0 / 0
Cache на основе ConcurrentHashMap. Метод computeIfAbsent блокируется.
    #39897281
vas0
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rabiter
А вы что думаете?
Если бы в моей голове родилась какая-нибудь мысль, она бы умерла от одиночества ©
...
Рейтинг: 0 / 0
2 сообщений из 2, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / Cache на основе ConcurrentHashMap. Метод computeIfAbsent блокируется.
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]