首先明白LRU算法的意思,LRU是局部性原理的一种体现。LRU算法表示一条数据使用后,那么下次他还可能再次被使用。当某个使用者,再次使用调用数据时优先拿到最近使用过的数据。
那么这个最近使用过的数据应该如何存储:目前我所知道的方法,使用栈作衡量数据活跃程度的标志flag。如下图表示一个栈,如果第一次取出key,得到这个key后在缓存中拿到数据,然后再将这个key加入这个栈中。这样这个key活跃在栈顶,也就表示最近使用的。
如果这是我想取得key4这个数据,那么取出key4,然后再压栈,这样key4存在栈顶中。
key4就表示了最近使用的数据。
通过上面的综述,实现LRU缓存需要一个数组队列来模拟一个栈。最近加入的数据放入栈顶。
初始化数组和数据结构。
private int cacheSize;
private Map cache;
private List keyList;
/**
* 初始化的构造方法
* keyList数组队列来模拟一个栈
*/
public LruCacheController() {
this.cacheSize = 100;
this.cache = Collections.synchronizedMap(new HashMap());
this.keyList = Collections.synchronizedList(new LinkedList());
}
上面的代码中,之所以使用了数组的链表的数据结构去模拟栈,是因为栈的先进后出特性促使最活跃的数据存放栈顶,数组的连续存储快速遍历特性,提供访问性能。
缓存中存放一个数据时,缓存的map中已经加满,就删除最后一条数据。也就是队列中最早加入的数据也就是第一条。取出第一条后,取出的数据就是map缓存的key,然后拿到这个key在缓存map中删掉。
public void putObject(Object key, Object value) {
cache.put(key, value);
keyList.add(key);
//缓存的map中已经加满,就删除最后一条数据
if (keyList.size() > cacheSize) {
try {
Object oldestKey = keyList.remove(0);
cache.remove(oldestKey);
} catch (IndexOutOfBoundsException e) {
// ignore
}
}
}
获取到一个数据方法。如果第一次取出key,得到这个key后再缓存中拿到数据,然后再将这个key压入keyList栈中。这样这个key活跃在keyList栈顶,也就表示最近使用的。
public Object getObject(Object key) {
Object result = cache.get(key);
keyList.remove(key);
//如果缓存中存在key对应的数据,这个key是缓存中有效的key,将key压keyList栈
if (result != null) {
keyList.add(key);
}
return result;
}
结论:keyList表示一个flag,标识着哪些数据应该被淘汰,也就是由这个keyList栈去控制,他们的活跃程度,根据在keyList的位置判断是否活跃,如果第一个0下标里,是没有被使用过的,可以被淘汰的。
水平原因可能存在错误,希望指正 chenrui@marsdl.com