LRU表示Least Recently Used,即最近最少被使用的页面替换算法。其理论基础是局部性原理,也就是说最近被访问的对象将在不久以后再次被访问。
对于LRU算法,可以使用一个链表和hashmap来实现。链表中的节点表示缓存的页面,链表中的第一个元素就是要被替换的元素,所以替换的复杂度是O(1)。同时,还维护一个hashmap来建立访问对象和缓存页面的映射关系。
当需要访问某个对象时,先从hashmap中查看该对象是否在缓存中,如果在,则将该缓存页面从链表中取出并插入到链表尾部,并访问对象。否则,从链表头取出一个缓存页面,将要访问的对象写入该缓存并插入到链表尾部,并且在hashmap中更新该项。这样,所有最近被访问的页面总是处于链表的尾部,即表头的元素表示最近最少被使用的可替换的页面。
LRU的实现
在JDK1.5中,LinkedHashMap已经实现了LRU的功能,只需要根据需要重写removeEldestEntry就行了。LinkedHashMap维护着一个运行于所有条目的双向链表。有了这个双向链表,就可以在迭代的时候按照插入的顺序迭代出元素,或者通过LRU算法迭代元素。
在LinkedHashMap的构造方法中,你可以指定accessOrder参数,当其为true时,将按照LRU算法对entry进行遍历;当其为false时,按照插入的顺序进行遍历。其值默认为true。想要详细了解LinkedHashMap可参见 http://boy00fly.iteye.com/blog/1144691
这里贴一个使用LinkedHashMap实现LRU的线程安全的代码
http://www.iteye.com/topic/123856
import java.util.LinkedHashMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> { private final int maxCapacity; private static final float DEFAULT_LOAD_FACTOR = 0.75f; private final Lock lock = new ReentrantLock(); public LRULinkedHashMap(int maxCapacity) { super(maxCapacity, DEFAULT_LOAD_FACTOR, true); this.maxCapacity = maxCapacity; } @Override protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) { return size() > maxCapacity; } @Override public V get(Object key) { try { lock.lock(); return super.get(key); } finally { lock.unlock(); } } @Override public V put(K key, V value) { try { lock.lock(); return super.put(key, value); } finally { lock.unlock(); } } }