使用 队列数组通过模拟栈 实现LRU缓存

首先明白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下标里,是没有被使用过的,可以被淘汰的。

水平原因可能存在错误,希望指正 [email protected]

猜你喜欢

转载自blog.csdn.net/Hello_Ray/article/details/84972328