java中的LRU

来源:互联网 发布:js 修改display 编辑:程序博客网 时间:2024/05/02 18:19

LRU = Least Recently Used 近期最少使用算法,用于缓存有限个对象,把不经常使用的对象重集合中移除


使用场景:比如游戏中只缓存一千个玩家数据,当超过一千时,把在缓存中停留时间最长的玩家数据移除



java中LinkedHashMap实现了LRU, 构造方法为LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) , 如果accessOrder为true表示使用LRU


例子:

public class Tt {public static void main(String[] args) {LinkedHashMap<Integer, String> LRU = new LinkedHashMap<Integer, String>(16, 0.75f, true);LRU.put(1, "111");LRU.put(2, "222");LRU.put(3, "333");LRU.put(4, "444");//输出结果 1 2 3 4print(LRU);
<span style="white-space:pre"></span>//这里访问一下LRU.get(2);//输出结果 1 3 4 2print(LRU);}static void print(LinkedHashMap<Integer, String> lru){Iterator<String> iterator = lru.values().iterator();for(;iterator.hasNext();){String next = iterator.next();System.out.print(next);System.out.print("---");}System.out.println("");}}

原理:

LinkedHashMap继承HashMap, 重写了HashMap中的一些方法,
LinkedHashMap中,使用了一个双向链表代替了HashMap中的单向链表LinkedHashMap中有一个header节点
每次放入新元素时都插入到header的前面( e.addBefore(header);), header.after是指向链表最前面的元素每次调用get方法,双向链表中会把get的元素删除,然后插入到header前面,这样最前面的元素也就是最近没有被访问的


每次添加新的元素后都会判断是否移除最老的元素

// Remove eldest entry if instructed, else grow capacity if appropriate        Entry<K,V> eldest = header.after;        if (removeEldestEntry(eldest)) {            removeEntryForKey(eldest.key);        } else {            if (size >= threshold)                resize(2 * table.length);        }

removeEldestEntry(eldest)

默认返回false,表示不移除,如果返回true,会移除header.after所指向的元素,也就是最老的元素


一般重写removeEldestEntry方法 return size() > 500; 500是LRU需要缓存的元素个数





关于源代码的一点思考:

为了使用HashMap的特点,但又要实现LRU, 采用了重写HashMap中的某些方法, 

removeEldestEntry(eldest)在HashMap中只是简单的返回false,在java中有很多地方都这样使用,在必要的时候重写,已产生不同的行为,因为这里不能用抽象方法,所以简单的返回一个值
</pre><pre name="code" class="java">突然想到面向对象设计原则:单一职责,开闭原则,依赖抽象,分离接口,里斯替换,
当作为LRU使用时,LinkedHashMap违反了<span style="font-family: Arial, Helvetica, sans-serif;">里斯替换,子类替换父类时,产生了不一样的行为(put时可能会移除某些元素)</span>




0 0
原创粉丝点击