Какой набор Java я должен использовать для реализации ориентированного на многопотоковое исполнение кэша?

Я надеюсь реализовывать простой кэш, не делая слишком большой работы (естественно). Мне кажется, что один из стандартных наборов Java должен быть достаточным с небольшой дополнительной работой. А именно, я храню ответы с сервера, и ключи могут или быть строкой URL запроса или хэш-кодом, сгенерированным от URL.

Я первоначально думал, что смогу использовать a WeakHashMap, но похоже, что метод вынуждает меня справиться, какие объекты я хочу иметь в наличии, и любые объекты, которыми я не управляю с сильными ссылками, сразу отметены. Если я испытываю a ConcurrentHashMap из SoftReference значения вместо этого? Или они будут очищены довольно настойчиво также?

Я теперь смотрю на LinkedHashMap класс. С некоторыми модификациями это выглядит многообещающим для кэша MRU. Какие-либо другие предложения?

Какой бы ни набор, который я использую, я должен попытаться вручную сократить значения LRU, или я могу доверить VM для смещения против исправления объектов, к которым недавно получают доступ?

К вашему сведению я разрабатываю на Android, таким образом, я предпочел бы не импортировать любые сторонние библиотеки. Я имею дело с очень маленькой "кучей" (16 - 24 МБ), таким образом, VM, вероятно, довольно стремится исправить ресурсы. Я предполагаю, что GC будет агрессивен.

10
задан Neil Traft 28 July 2010 в 16:42
поделиться

5 ответов

Если вы используете ключи на основе SoftReference , виртуальная машина будет смещать (сильно) по отношению к недавно доступным объектам. Однако было бы довольно сложно определить семантику кэширования - единственная гарантия, которую дает SoftReference (вместо WeakReference), состоит в том, что она будет очищена до того, как будет выдано OutOfMemoryError . Для реализации JVM было бы совершенно законно относиться к ним так же, как и к WeakReferences, и в этот момент вы можете получить кеш, который ничего не кеширует.

Я не знаю, как все работает на Android, но с недавними JVM Sun можно настроить поведение SoftReference с помощью параметра командной строки -XX: SoftRefLRUPolicyMSPerMB, который определяет количество миллисекунд, в течение которых будет доступен мягко доступный объект. сохраняется за 1 МБ свободной памяти в куче. Как видите, получить какое-либо предсказуемое поведение продолжительности жизни будет исключительно сложно, с дополнительными проблемами, поскольку этот параметр является глобальным для всех мягких ссылок в виртуальной машине и не может быть настроен отдельно для использования отдельными классами. SoftReferences (есть вероятность, что каждому пользователю потребуются разные параметры).


Самый простой способ создать кэш LRU - это расширить LinkedHashMap , как описано здесь .Поскольку вам нужна потокобезопасность, простейший способ изначально ее расширить - просто использовать Collections.synchronizedMap в экземпляре этого настраиваемого класса для обеспечения безопасного параллельного поведения.

Остерегайтесь преждевременной оптимизации - если вам не нужна очень высокая пропускная способность, теоретически неоптимальные накладные расходы грубой синхронизации вряд ли будут проблемой. И хорошие новости: если профилирование показывает, что вы работаете слишком медленно из-за сильной конкуренции блокировок, у вас будет достаточно информации об использовании вашего кеша во время выполнения, чтобы вы могли предложить подходящую альтернативу без блокировки (возможно, на основе ConcurrentHashMap с некоторой ручной обработкой LRU) вместо того, чтобы угадывать его профиль нагрузки.

6
ответ дан 3 December 2019 в 23:48
поделиться

Для синхронизации фреймворк Collections предоставляет синхронизированную карту:

Map<V,T> myMap = Collections.synchronizedMap(new HashMap<V, T>());

Вы можете обернуть это или обработать логику LRU в объекте кэша.

1
ответ дан 3 December 2019 в 23:48
поделиться

Мне нравятся коллекции Apache Commons LRUMap

0
ответ дан 3 December 2019 в 23:48
поделиться

LinkedHashMap легко использовать для кеширования. Это создает кэш MRU размером 10.

private LinkedHashMap<File, ImageIcon> cache = new LinkedHashMap<File, ImageIcon>(10, 0.7f, true) {
    @Override
    protected boolean removeEldestEntry(Map.Entry<File, ImageIcon> eldest) {
        return size() > 10;
    }
};

Я думаю, вы можете создать класс с синхронизированными делегатами для этой LinkedHashMap. Простите меня, если я неправильно понимаю синхронизацию.

5
ответ дан 3 December 2019 в 23:48
поделиться

www.javolution.org имеет несколько интересных функций - синхронизированные быстрые коллекции. В вашем случае стоит попробовать, поскольку он также предлагает некоторые изящные улучшения для небольших устройств, таких как Android.

1
ответ дан 3 December 2019 в 23:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: