Легко, просто использовать LRU кеш в Java - PullRequest
61 голосов
/ 22 октября 2008

Я знаю, что это просто реализовать, но я хочу использовать то, что уже существует.

Проблема, которую я хочу решить, состоит в том, что я загружаю конфигурацию (из XML, поэтому я хочу кешировать ее) для разных страниц, ролей, ... поэтому комбинация входных данных может значительно вырасти (но в 99% не будет). Чтобы справиться с этим 1%, я хочу иметь максимальное количество элементов в кеше ...

Пока я не нашел org.apache.commons.collections.map.LRUMap в Apache Commons, и он выглядит хорошо, но хочу проверить и кое-что еще. Любые рекомендации?

Ответы [ 5 ]

98 голосов
/ 22 октября 2008

Вы можете использовать LinkedHashMap (Java 1.4+):

// Create cache
final int MAX_ENTRIES = 100;
Map cache = new LinkedHashMap(MAX_ENTRIES+1, .75F, true) {
    // This method is called just after a new entry has been added
    public boolean removeEldestEntry(Map.Entry eldest) {
        return size() > MAX_ENTRIES;
    }
};

// Add to cache
Object key = "key";
cache.put(key, object);

// Get object
Object o = cache.get(key);
if (o == null && !cache.containsKey(key)) {
    // Object not in cache. If null is not a possible value in the cache,
    // the call to cache.contains(key) is not needed
}

// If the cache is to be used by multiple threads,
// the cache must be wrapped with code to synchronize the methods
cache = (Map)Collections.synchronizedMap(cache);
26 голосов
/ 28 сентября 2011

Это старый вопрос, но для потомков я хотел бы перечислить ConcurrentLinkedHashMap , который в отличие от LRUMap является поточно-ориентированным. Использование довольно просто:

ConcurrentMap<K, V> cache = new ConcurrentLinkedHashMap.Builder<K, V>()
    .maximumWeightedCapacity(1000)
    .build();

И в документации есть несколько хороших примеров , например, как сделать размер кэша LRU основанным на количестве элементов.

12 голосов
/ 31 июля 2012

Вот моя реализация, которая позволяет мне хранить в памяти оптимальное количество элементов.

Дело в том, что мне не нужно отслеживать, какие объекты используются в настоящее время, поскольку я использую комбинацию LinkedHashMap для объектов MRU и WeakHashMap для объектов LRU. Таким образом, емкость кеша не меньше размера MRU плюс все, что позволяет мне сохранить GC. Всякий раз, когда объекты падают с MRU, они отправляются в LRU до тех пор, пока GC будет иметь их.

public class Cache<K,V> {
final Map<K,V> MRUdata;
final Map<K,V> LRUdata;

public Cache(final int capacity)
{
    LRUdata = new WeakHashMap<K, V>();

    MRUdata = new LinkedHashMap<K, V>(capacity+1, 1.0f, true) {
        protected boolean removeEldestEntry(Map.Entry<K,V> entry)
        {
            if (this.size() > capacity) {
                LRUdata.put(entry.getKey(), entry.getValue());
                return true;
            }
            return false;
        };
    };
}

public synchronized V tryGet(K key)
{
    V value = MRUdata.get(key);
    if (value!=null)
        return value;
    value = LRUdata.get(key);
    if (value!=null) {
        LRUdata.remove(key);
        MRUdata.put(key, value);
    }
    return value;
}

public synchronized void set(K key, V value)
{
    LRUdata.remove(key);
    MRUdata.put(key, value);
}
}
1 голос
/ 19 февраля 2012

Здесь - это очень простой и легкий в использовании кэш LRU в Java. Хотя это коротко и просто, это качество продукции. Код объяснен (смотрите README.md) и имеет несколько модульных тестов.

1 голос
/ 21 декабря 2011

У меня тоже была такая же проблема, и я не нашел хороших библиотек ... поэтому я создал свою собственную.

simplelrucache обеспечивает многопоточное, очень простое, нераспределенное LRU-кэширование с поддержкой TTL. Предоставляет две реализации

  • Параллельный на основе ConcurrentLinkedHashMap
  • Синхронизировано на основе LinkedHashMap

Вы можете найти его здесь .

...