我有一个使用LinkedHashMap的LRU缓存的简单实现。
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;
}发布于 2012-01-03 04:12:56
首先,正确使用泛型。
其次,如果您需要缓存大小,那么为什么要跟踪它呢?我会认为那是某种错误。
第三,如果您真的想惹恼大多数真正专业的java开发人员和课程指导人员(也就是说,那些编写Java代码的人就像用C#、C++或Pascal编程一样),请在类名和变量名前加上前缀。如果你不想这样做,不要这样做。
第四,我个人更喜欢自己来处理同步。这样,如果类被扩展为包含在映射中执行两个或多个操作的某个方法,我将不会破坏它。我添加了atomicGetAndSet方法来显示这一点。如果我依赖于Collections.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;
}
}发布于 2014-08-26 08:31:39
来自LinkedHashMap的javadoc的说明:
注意,如果将键重新插入到映射中,则插入顺序不会受到影响。
因此,这将不是一个LRU地图,除非您确保所有的键是唯一的。
然而,在文件中还有:
提供了一个特殊的构造函数来创建一个链接的散列映射,其迭代顺序是最近一次访问其条目的顺序,从最近访问到最近访问(访问顺序)。这种地图非常适合于建立LRU缓存。
发布于 2015-01-20 14:23:53
通过使用LinkedHashMap在生产代码中实现LRU缓存,我想说:为什么不继续实现完整的Map接口呢?在某种程度上,您可能会意识到您需要一个size()方法和一个entrySet()方法,可能还需要一些类似于Map的方法,所以最好通过遍历所有其他公共Map方法,使LRUCache成为包含的fCacheMap的外观。这就打开了一个实用程序类的整个世界,如果需要的话,这些类可以用于检查或操作Maps。
就像这样:
public class LRUCache<E> implements Map<Object, E> {
// ...
public int size()
{
return fCacheMap.size(key);
}
// etc...
}当然,您可以决定Map接口的一个子集是足够的,也许可以使用类似于Collection的东西。这完全取决于您如何设想如何使用您的LRUCache。
https://codereview.stackexchange.com/questions/3138
复制相似问题