Как реализовать ConcurrentHashMap с функциями, аналогичными LinkedHashMap?

StackOverflow https://stackoverflow.com/questions/1815646

Вопрос

Я использовал LinkedHashMap с accessOrder истиной, а также разрешил в любое время максимум 500 записей в качестве кэша LRU для данных. Но из-за проблем с масштабируемостью я хочу перейти к некоторой поточно-ориентированной альтернативе. ConcurrentHashMap кажется хорошим в этом отношении, но в нем отсутствуют функции removeEldestEntry(Map.Entry e) и <=>, которые можно найти в <=>. Может кто-нибудь указать на какую-то ссылку или помочь мне облегчить реализацию.

Это было полезно?

Решение

Недавно я сделал нечто подобное с ConcurrentHashMap<String,CacheEntry>, где CacheEntry оборачивает фактический элемент и добавляет статистику удаления кэша: время истечения, время вставки (для выселения FIFO / LIFO), время последнего использования (для выселения LRU / MRU), число попаданий (для выселения LFU / MFU) и т. д. Фактическое выселение синхронизируется и создает ArrayList<CacheEntry> и выполняет для него Collections.sort (), используя соответствующий компаратор для стратегии выселения. Так как это дорого, каждое выселение сбрасывает нижние 5% CacheEntries. Я уверен, что настройка производительности поможет, хотя.

В вашем случае, поскольку вы делаете FIFO, вы можете оставить отдельный ConcurrentLinkedQueue . Когда вы добавляете объект в ConcurrentHashMap, выполняйте ConcurrentLinkedQueue.add () этого объекта. Если вы хотите удалить запись, выполните ConcurrentLinkedQueue.poll (), чтобы удалить самый старый объект, а затем удалите его и из ConcurrentHashMap.

Обновление. Другие возможности в этой области включают в себя синхронизацию коллекций Java. обертка и Java 1.6 ConcurrentSkipListMap .

Другие советы

Вы пытались использовать одно из многих решений для кэширования, таких как ehcache? Вы можете попробовать использовать LinkedHashMap с ReadWriteLock. Это даст вам одновременный доступ для чтения.

Сейчас это может показаться старым, но, по крайней мере, только для моего собственного отслеживания истории, я собираюсь добавить свое решение здесь: я объединил ConcurrentHashMap, который отображает K - > подкласс WeakReference, ConcurrentLinkedQueue и интерфейс это определяет десериализацию объектов-значений на основе K для правильного запуска кэширования LRU. Очередь содержит строгие ссылки, и GC выселяет значения из памяти, когда это необходимо. Отслеживание размера очереди связано с AtomicInteger, так как вы не можете реально проверить очередь, чтобы определить, когда выселить. Кеш будет обрабатывать выселение из / добавление в очередь, а также управление картой. Если GC вытеснил значение из памяти, реализация интерфейса десериализации будет обрабатывать получение значения обратно. У меня также была другая реализация, которая включала в себя буферизацию на диск / повторное чтение буферизованного, но это было намного медленнее, чем решение, которое я выложил здесь, так как мне пришлось синхронизировать буферизацию / чтение.

Вы упоминаете о том, что хотите решить проблемы масштабируемости с помощью " thread-safe " альтернатива. " Потокобезопасность " Здесь означает, что структура терпима к попыткам одновременного доступа, поскольку она не будет повреждена при одновременном использовании без внешней синхронизации. Однако такой допуск не обязательно помогает улучшить & Масштабируемость & Quot ;. В самом простом, хотя обычно ошибочном, подходе вы попытаетесь синхронизировать свою структуру внутри себя и все же оставить неатомарные операции check-then-act небезопасными.

Кэши LRU требуют, по крайней мере, некоторой осведомленности об общей структуре. Им нужно что-то вроде количества членов или размера членов, чтобы решить, когда выселять, а затем они должны быть в состоянии скоординировать выселение с одновременными попытками чтения, добавления или удаления элементов. Попытка уменьшить синхронизацию, необходимую для одновременного доступа к & Quot; main & Quot; структура борется с вашим механизмом выселения и вынуждает вашу политику выселения быть менее точной в своих гарантиях.

В текущем принятом ответе упоминается " когда вы хотите удалить запись " ;. В этом и заключается загвоздка. Как вы знаете, когда вы хотите выселить запись? Какие другие операции нужно приостановить, чтобы принять это решение?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top