LinkedHashMap как LRU-кэш


У меня есть простая реализация для дисциплины LRU кэша с помощью LinkedHashMap.

  • Я хочу, чтобы это было как можно более универсальный.
  • Это не для использования в производстве, только практика, поэтому мне плевать если его тщательно надежными, насколько это правильно. Однако, я буду приветствовать любые комментарии, особенно те, что может сделать это лучше с простые изменения :)
  • Есть ли другие способы это сделать?
class LRUCache<E> {

    @SuppressWarnings("unchecked")
    LRUCache(int size)
    {
        fCacheSize = size;

        // If the cache is to be used by multiple threads,
        // the hashMap must be wrapped with code to synchronize 
        fCacheMap = Collections.synchronizedMap
        (
            //true = use access order instead of insertion order
            new LinkedHashMap<Object,E>(fCacheSize, .75F, true)
            {                                
                @Override
                public boolean removeEldestEntry(Map.Entry eldest)  
                {
                    //when to remove the eldest entry
                    return size() > 99 ;   //size exceeded the max allowed
                }
            }
        );
    }

    public void put(Object key, E elem)
    {
        fCacheMap.put(key, elem);
    }

    public E get(Object key)
    {
        return fCacheMap.get(key);
    }

    private Map<Object,E> fCacheMap;
    private int fCacheSize;
}


14777
11
задан 27 июня 2011 в 02:06 Источник Поделиться
Комментарии
1 ответ

Во-первых, использовать дженерики правильно.

Во-вторых, зачем вам отслеживать размер кэша в случае, когда вам это нужно, вы получаете жестко 99? Смею предположить, что была какая-то ошибка.

В-третьих, если вы действительно хотите, чтобы раздражать по-настоящему профессиональные Java-разработчики и инструкторский курс (меня.е, а не Эти, что писать Java-код, как если бы они были программирование на C#, C++ или Паскаль), префикс свой класс и имена переменных. Если вы не хотите делать это, не делайте этого.

В-четвертых, я бы лично предпочел справиться сам синхронизации. Таким образом, если класс будет расширена, чтобы включить какой-то метод, который делает две или более операций на карте, я не нарушу его. Я добавил atomicGetAndSet способ показать это. Если бы я опирался в синхронизации представленной коллекции.synchronizedMap вместо моих, atomicGetAndSet способ не быть атомной и оно разорвется, если LRUCache случаях используются одновременно.

Имея это в виду, ваш код стал таким:

public class LRUCache<K, V> {

private final Map<K, V> cacheMap;

public LRUCache(final int cacheSize) {

// true = use access order instead of insertion order.
this.cacheMap = new LinkedHashMap<K, V>(cacheSize, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
// When to remove the eldest entry.
return size() > cacheSize; // Size exceeded the max allowed.
}
};
}

public synchronized void put(K key, V elem) {
cacheMap.put(key, elem);
}

public synchronized V get(K key) {
return cacheMap.get(key);
}

public synchronized V atomicGetAndSet(K key, V elem) {
V result = get(key);
put(key, elem);
return result;
}
}

10
ответ дан 3 января 2012 в 04:01 Источник Поделиться