1 结构示意图
2 源码实现
package classloader.lc;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* LinkedHashMap实现Map的接口,和HashMap不同的是维持了一个所有entries的双向链表,
* 并持有一个该有序链表的迭代器,并有两个Entry<K,V>引用transient LinkedHashMap.Entry<K,V> head,tail
* 分别指向链表的首部和尾部,最常使用的元素会放到链表的尾部,链表的头部为最不常用的数据,
* 同时插入一个新元素也会插入到尾部,我们可以用这个特性来实现LRU(最近最不常使用)缓存;
* The tail (youngest) of the doubly linked list.
* The head (eldest) of the doubly linked list.
*
* 查询元素 get-->accessOrder == true --> afterNodeAccess move node to last 实现最近访问移动到尾部;
*
* boolean removeEldestEntry(Map.Entry)该方法返回值为true时,会删除最近最不常使用的元素,
* 也就是double-link的头部节点,当插入一个新节点之后removeEldestEntry()方法会被put()、putAll()方法调用,
* 我们可以通过override该方法,来控制删除最旧节点的条件
* 即 put--> afterNodeInsertion---->removeEldestEntry 需要自定义实现保留元素的长度
*
*/
class LRUCache extends LinkedHashMap<Integer, Integer> {
private int maxSize;
public LRUCache(int capacity) {
// 第三个参数表示开启lru
super(capacity, 0.75f, true);
this.maxSize = capacity;
}
//return -1 if miss
public int get(int key) {
Integer v = super.get(key);
return v == null ? -1 : v;
}
public void put(int key, int value) {
super.put(key, value);
}
// Here is my implementation by using LinkedHashMap in AccessOrder.
// It will move the latest accessed element to the front which only
// incurs O(1) overhead because the underlying elements are
// organized in a doubly-linked list while also are indexed by hash function.
// So the get/put/top_newest_one operations all cost O(1).
// 当前size()大于了maxSize便删掉头部的元素, 先从map中移除,再从双向链表中移除
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return this.size() > maxSize; //must override it if used in a fixed cache
}
}
3 小结
- 1 整体结构 hashmap + 双向链表
- 2 LRU缓存