LRU least recently used 与LinkedHashMap

LRU ,最近最少使用淘汰算法,用于存储限量limit的数据,不超过 limit的数据将直接存储,若超过limit,则将”最老的数据”淘汰掉。使用LinkedHashMap实现。

LinkedHashMap相较于HashMap增加了排序,但又比TreeMap less cost


LinkedHashMap继承自HashMap,在entry间维系一个双向链表,但具有预指定迭代顺序,通常为插入顺序。这种情况下,如果key被re-inserted,其顺序不会改变,即更新key并不会改变原有顺序。

但还可以指定排序为按entry最后访问排序。

A special {@link #LinkedHashMap(int,float,boolean) constructor} is provided to create a linked hash map whose order of iteration is the order in which its entries were last accessed, from least-recently accessed to most-recently (<i>access-order</i>).  This kind of map is well-suited to building LRU caches. 

其基础api与HashMap时间cost类似,Performance is likely to be just slightly below that of <tt>HashMap</tt>

LinkedHashMap迭代器耗时与map的size相关,而非capacity。
而HashMap迭代器耗时与capacity相关。

故LinkedHashMap的初始capacity的选取并没有那么重要。


修改已存在的key时,对于以插入顺序排序的LinkedHashMap并非结构性修改structural modification ,而对于以访问顺序排序的LinkedHashMap则是structural modification 。

structural modification 与fail-fast机制相关,对于非线程安全容器,获取迭代器时修改数据会抛出ConcurrentModificationException异常,迭代器本身remove方法除外。

* A structural modification is any operation that adds or deletes one or more
* mappings or, in the case of access-ordered linked hash maps, affects
* iteration order. In insertion-ordered linked hash maps, merely changing
* the value associated with a key that is already contained in the map is not
* a structural modification. <strong>In access-ordered linked hash maps,
* merely querying the map with <tt>get</tt> is a structural modification.
* </strong>)


组件,除继承自hashmap外,还新增了指向头尾节点的指针before, after。

static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}

指定排序:accessOrder  默认构造方法均使用false,除非指定accessOrder。

true:访问顺序

false:插入顺序

/**
* The iteration ordering method for this linked hash map: <tt>true</tt>
* for access-order, <tt>false</tt> for insertion-order.
*
* @serial
*/
final boolean accessOrder;


基础方法与HashMap基本相似

但重写了get()方法

public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return null;
if (accessOrder) --------------------------------------------------------------如果设置为按访问顺序排序,则访问数据后将其移至链表尾部。
afterNodeAccess(e);
return e.value;
}

访问数据后将其移至链表尾部

void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}



移除最老entry,调用put方法和putAll方法后,判断是否需要移除后调用,用于保持缓存的最大容量不溢出。
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
总是return false 时,表明其永不会移除最老元素。









猜你喜欢

转载自www.cnblogs.com/wanghuanyeah/p/12038255.html