本文,只要讲下基于LinkedHashMap来实现LRU结构,了解LRU的实现思路,LinkedHashMap的实现结构,也基本熟悉了。
下面的图转自:http://uule.iteye.com/blog/1522291
LinkedHashMap添加新元素时,调用put方法。
put(K k, V v)->HashMap.put(k, v)->如果是新的k, 即新的map元素->HashMap.addEntry(int hash, K key, V value, int bucketIndex)->LinkedHashMap重写了addEntry方法->
LinkedHashMap.addEntry(hash, k, v, bucketIndex);
下面看看LinkedHashMap的addEntry方法:
void addEntry(int hash, K key, V value, int bucketIndex) {
super.addEntry(hash, key, value, bucketIndex); //1处
// Remove eldest entry if instructed
Entry<K,V> eldest = header.after;
if (removeEldestEntry(eldest)) {//2处
removeEntryForKey(eldest.key);
}
}
看看上面源码的1处,首先会将map元素put进去,源码的2处判断map元素添加了进去,是否需求删去最旧的元素,下面是LinkedHashMap的源码。
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
LinkedHashMap默认是不会删除最老的元素的。
从1处,super.addEntry,即是调用的HashMap的addEntry方法,看看HashMap的addEntry源码:
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
createEntry(hash, key, value, bucketIndex); //3处
}
从上面的3处,创建一个新的Entry,LinkedHashMap重写了HashMap的createEntry方法:
void createEntry(int hash, K key, V value, int bucketIndex) {
HashMap.Entry<K,V> old = table[bucketIndex];
Entry<K,V> e = new Entry<>(hash, key, value, old);
table[bucketIndex] = e;
e.addBefore(header); //4处
size++;
}
从1处中的header,是LinkedHashMap的链头,LinkedHashMap创建时会初始化header:
void init() {
header = new Entry<>(-1, null, null, null);
header.before = header.after = header;
}
下面是LinkedHashMap.Entry的addBefore方法:
private void addBefore(Entry<K,V> existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
}
这样可以将新创建的Entry链接到链头head之前,head之后是新创建的Entry,形成了双向链表。
所以如果需要自定义LRU map,即是,least recently used(最近最少使用)的功能,则只重写removeEldestEntry(java.util.Map.Entry<K, V> eldest)方法就好了。
一般来说,自定义LRU,会定义好map的size,只要map的元素数量超过这个size,则会删除最老的元素即可,下面是部分代码:
private static class LRUCache<K, V>{
private int cacheSize;
private LinkedHashMap<K, V> linkedHashMap;
public LRUCache(int cacheSize){
this.cacheSize = cacheSize;
this.linkedHashMap = new LinkedHashMap<K, V>(this.cacheSize, 0.75f, false){
private static final long serialVersionUID = 1L;
@Override
protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
return size() > LRUCache.this.cacheSize;
}
};
}
//其他的put,get,remove,clear,toString,size方法等
}
其他的方法如put,get等等,调用LinkedHashMap的就可以了。
用LinkedHashMap来实现LRU,主要是基于HashMap的底层结构来保存数据元素。