简介
我使用ArrayDeque
并使用Generics
解决方案实施了一个带有LRU策略的简单缓存:
public class Cache<T> extends ArrayDeque<T> implements Serializable {
private static final long serialVersionUID = 1L;
private int MAX_SIZE;
public Cache(int maxSize) {
MAX_SIZE = maxSize;
}
public void store(T e) {
if (super.size() >= MAX_SIZE) {
this.pollLast();
}
this.addFirst(e);
}
public T fetch(T e) {
Iterator<T> it = this.iterator();
while (it.hasNext()) {
T current = it.next();
if (current.equals(e)) {
this.remove(current);
this.addFirst(current);
return current;
}
}
return null;
}
}
问题
当我实例化类并推送一个元素时,
Cache<CachedClass> cache = new Cache<CachedClass>(10);
cache.store(new CachedClass());
此时队列中不包含任何内容。
为什么会这样?
观察
顺便说一下,CachedClass
会覆盖方法.equals()
。
测试
public class CacheTest {
@Test
public void testStore() {
Cache<Integer> cache = new Cache<Integer>(3);
cache.store(1);
assertTrue(cache.contains(1));
cache.store(2);
cache.store(3);
cache.store(4);
assertEquals(cache.size(), 3);
}
@Test
public void testFetch() {
Cache<Context> cache = new Cache<Context>(2);
Context c1 = new Context(1);
Context c2 = new Context(2);
cache.store(c1);
cache.store(c2);
assertEquals((Context) cache.peekFirst(), (new Context(2)));
Context c = cache.fetch(c1);
assertTrue(c == c1);
assertEquals(cache.size(), 2);
assertEquals((Context) cache.peekFirst(), (new Context(1)));
}
}
编辑它成功通过了两项测试。
它通过了第一次测试。它无法在
上抛出AssertException
assertTrue(cache.peekFirst() == 1);
第二次测试,
答案 0 :(得分:1)
LinkedHashMap的Javadoc说
“这种地图非常适合构建LRU缓存。”
你真的需要有理由忽视这一点。我的猜测是,在使用Map的实现中,性能将无法区分,并且在使用Map时获得的性能要好得多 - 但是,嘿,为什么不运行自己的基准测试。
最后,您的实现(以及LinkedHashMap提供的实现)不是线程安全的。如果这对您来说是个问题,则同步逻辑将增加性能开销。
答案 1 :(得分:0)
我在主要方法中这样做:
Cache<Integer> cache = new Cache<Integer>(10);
cache.store(new Integer(0));
System.out.println(cache.size()); // prints 1
Integer foo = cache.fetch(new Integer(0));
System.out.println(foo == null); // prints false
并打印1,因此Cache
中有1个元素。工作正常。
用于获取CachedClass
muss覆盖equals()
。您的代码无需更改就可以完美地运行。
答案 2 :(得分:0)
我使用LinkedHashMap作为LRU缓存。
public static <K,V> Map<K,V> lruCache(final int maxSize) {
return new LinkedHashMap<K,V>(maxSize*4/3, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return size() > maxSize;
}
};
}
一个重要的区别是密钥与值相关联。如果你将一个缓存作为一个集来实现,你可以做的就是确认你已经拥有的对象是否在缓存中,这对我来说并不那么有用。
测试
@Test
public void testStore() {
Map<Integer, String> cache = lruCache(3);
cache.put(1, "one");
assertEquals("one", cache.get(1));
cache.put(2, "two");
cache.put(3, "three");
cache.put(4, "four");
assertEquals(cache.size(), 3);
assertEquals(null, cache.get(1));
}
@Test
public void testFetch() {
Map<Integer, String> cache = lruCache(3);
cache.put(1, "one");
cache.put(2, "two");
assertEquals((Integer) 1, cache.keySet().iterator().next());
String s = cache.get(1);
assertEquals("one", s);
assertEquals(cache.size(), 2);
assertEquals((Integer) 2, cache.keySet().iterator().next());
}