LRU原理与实现
一、LRU是什么
Least Recently Used,也就是最近最少使用,LRU缓存将最近最少使用的数据移除,让给最新读取的数据。而往往是最常读取的,也就是读取次数最多的。所以利用LRU缓存,我们可能提高系统的performance.
二、LRU的实现
- 实现方法一:使用 LinkedHashMap
使用LinkedHashMap的好处:

代码如下
public class MyLRUCache1<K,V>{
private static final float hashTableLoadFactor = 0.75f;
private LinkedHashMap<K,V > map ;
private int cacheSize ;
public MyLRUCache1( int cacheSize){
this.cacheSize = cacheSize ;
int hashTableCapacity = (int)Math.ceil(cacheSize/hashTableLoadFactor)+1;
//an anonymous inner class,true means accessOrder
map = new LinkedHashMap<K,V>(hashTableCapacity, hashTableLoadFactor, true) {
private static final long serialVersionID=1;
@Override
protected boolean removeEldestEntry(Entry<K, V> eldest) {
//在什么情况下进行回收
return size()> MyLRUCache1.this.cacheSize ;
}
};
}
public synchronized V get(K key){
return map.get(key) ;
}
public synchronized void put(K key,V value){
map.put(key, value) ;
}
public synchronized void clear (){
map.clear();
}
public synchronized int usedEntries(){
return map.size() ;
}
public synchronized Collection<Map.Entry<K,V>> getAll(){
return new ArrayList<Map.Entry<K,V>>(map.entrySet()) ;
}
}
测试方法
StringBuilder sb = new StringBuilder() ;
cache.put("1", "one"); //1
cache.put("2", "two"); //2 1
cache.put("3", "three"); //3 2 1
cache.put("4", "four"); //4 3 2
if (cache.get("2")== null)
throw new Error() ; //2 4 3
for (Map.Entry<String,String > e : cache.getAll()){
sb.append(e.getKey()+":"+e.getValue()+"\n");
}
cache.put("5", "five"); //5 2 4
cache.put("4", "second four");//4 5 2
//verify cache content
sb.append("cache used:"+cache.usedEntries()+"\n") ;
sb.append(cache.get("4")+"\n");
sb.append(cache.get("5")+"\n");
sb.append(cache.get("2")+"\n");
for (Map.Entry<String,String > e : cache.getAll()){
sb.append(e.getKey()+":"+e.getValue()+"\n");
}
tv.setText(sb.toString());
Log.d(TAG,sb.toString()) ;
结果如下
3:three
4:four
2:two
cache used:3
second four
five
two
4:second four
5:five
2:two
- 实现方法2:双链表+HashTable

源码如下
public class MyLRUCache2<K,V> {
private class Entry {
Entry prev ;
Entry next ;
V value ;
K key ;
}
private int cacheSize ;
private Hashtable<K, Entry> nodes ; //cache container
private int currentSize ;
private Entry first ; //header
private Entry last ; //last
public MyLRUCache2(int cacheSize ){
currentSize =0;
this.cacheSize = cacheSize ;
nodes = new Hashtable<>(cacheSize);
}
/**
*得到cache中的对象,并放到最前面
*/
public Entry get(K key ){
Entry node = nodes.get(key) ;
if (node!= null){
moveToHead(node);
return node;
}else {
return null ;
}
}
/**
*添加entry到hashtable
*/
public void put(K key, V value){
//先查看hashtable是否存在这个entry,如果存在,则只更新其value
Entry node = nodes.get(key) ;
if (node == null){
//缓存容器是否已经超过大小
if (currentSize>= cacheSize){
nodes.remove(last.key) ;
removeLast();
}else {
currentSize++;
}
node= new Entry();
}
node.value = value;
//将最新使用的节点放到链表头最新使用的
moveToHead(node) ;
nodes.put(key,node);
}
/**
* 将entry删除,删除只在cache满了才会被执行
*/
public void remove(K key){
Entry node = nodes.get(key) ;
//在链表中删除
if (node!= null){
if (node.prev!= null){
node.prev.next = node.next ;
}
if (node.next!= null){
node.next.prev = node.prev ;
}
if (last== node){
last = node.prev ;
}
if (first == node){
first = node.next ;
}
}
//在hashtable中删除
nodes.remove(key) ;
}
/**
* 删除链表尾部节点,也就是最少使用的缓存对象
*/
private void removeLast(){
// 链表尾部不为空,则将其指向空,删除链表尾部,
if (last!= null){
if (last.prev!= null){
last.prev.next = null ;
}else {
first = null ;
}
last= last.prev ;
}
}
/**
* 移动到链表头,表示这个节点是最新使用过的
*/
private void moveToHead( Entry node){
if (node == first)
return;
if (node.prev!= null){
node.prev.next = node.next;
}
if (node.next!= null){
node.next.prev = node.prev;
}
if (last== node){
last = node.prev ;
}
if (first!= null) {
node.next = first ;
first.prev = node;
}
first = node;
node.prev = null ;
if (last == null){
last = first ;
}
}
public void clear (){
first = null ;
last = null ;
currentSize =0;
}
}

浙公网安备 33010602011771号