LRU算法(缓存淘汰算法)通过继承或者组合

基于继承LinkedHashMap实现LRU算法:

  1. LinkedHashMap
    存储结构: 链表+散列表
    存储算法:LRU+哈希算法

  2. LinkedHashMap 特性
    记录元素添加顺序,访问数据
    线程不安全

  3. LRU算法:最近最少使用算法

class LruCache extends LinkedHashMap<String,Object> {

	private int maxCap;//最大容量
	public LruCache(int initialCapacity, float loadFactor, boolean accessOrder) {//initialCapacity初始规定容量, loadFactor 加载因子 一般是0.75f,accessOrder true基于访问顺序  false则是基于插入顺序	
		super(initialCapacity, loadFactor, accessOrder);
		// TODO Auto-generated constructor stub
		this.maxCap=initialCapacity;
	}
	@Override
	protected boolean removeEldestEntry(java.util.Map.Entry<String, Object> eldest) {
		// TODO Auto-generated method stub
		return size()>maxCap;
	}
}

public class testCache {
	public static void main(String[] args) {
		LruCache cache=new LruCache(4,0.75f,true);
		cache.put(" A", 10);
		cache.put("	C", 20);
		cache.put("	B", 60);
		cache.put("	D", 40);
		cache.put("	E", 50);
		cache.get("D");
		System.out.println(cache);
	}
}

基于组合Map(LinkedHashMap和HashMap)实现LRU算法
结构:

  • Cache接口
  • 用PerpetualCache实现类存储数据:HashMap 存数据
  • 用LruCache实现类实现缓存算法:LinkedHashMap 存访问记录

Cache接口

public interface Cache {
	public void putObject(Object key,Object value);//添加键值对方法
	
	public Object getObject(Object key);//通过键取值
	
	public Object removeObject(Object key);//通过键删除值
	
}

PerpetualCache实现类 用来存储数据

import java.util.HashMap;
import java.util.Map;

public class PerpetualCache implements Cache{
	private Map<Object, Object> cache=new HashMap<Object, Object>();//组合关系
	@Override
	public void putObject(Object key, Object value) {
		cache.put(key, value);
	}

	@Override
	public Object getObject(Object key) {
		return cache.get(key);
	}

	@Override
	public Object removeObject(Object key) {
		// TODO Auto-generated method stub
		return cache.remove(key);
	}
	public String toString() {
		return cache.toString();
	}
}

LruCache实现类 用来实现算法

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;

public class LruCache implements Cache{
	private  Cache cache;//接口类型组合,作用运行时多态
	private Map<Object, Object> keyMap;//组合关系
	private Object eldestKey;
	public LruCache(int maxCap,Cache cache) {
		this.cache=cache;
		keyMap=new LinkedHashMap<Object, Object>(maxCap,0.75f,true){
				@Override
				protected boolean removeEldestEntry(java.util.Map.Entry<Object, Object> eldest) {
				// TODO Auto-generated method stub
				boolean tooBig=keyMap.size()>maxCap;//判断当前集合的大小是否大于规定集合容量大小
				if(tooBig) {
					eldestKey=eldest.getKey();//当上述为true时,将要删除最早添加,且最近没有访问的值
				}
				return tooBig;
			}
		};
	}
	@Override
	public void putObject(Object key, Object value) {
		// TODO Auto-generated method stub
		
		cache.putObject(key, value);
		cycleOldKeyList(key);
		//第一添加键到HashMap集合,用来记录键值对数量,
		//第二查看是否HashMap已满,满的话要清除最早添加,且最近没有访问的值
	}

	@Override
	public Object getObject(Object key) {
		// TODO Auto-generated method stub
		keyMap.get(key);//keyMap记录访问顺序
		return cache.getObject(key);
	}

	@Override
	public Object removeObject(Object key) {
		// TODO Auto-generated method stub
		return cache.removeObject(key);
	}
	//判断是否有最早且最近没有访问的值,有的话就通过清除
	private void cycleOldKeyList(Object key) {
	    keyMap.put(key, key);
	    if (eldestKey != null) {
	      cache.removeObject(eldestKey);
	      eldestKey = null;
	    }
	  }
	public String toString() {
		return cache.toString();
	}
}

测试类1

public class test2 {
	public static void main(String[] args) {
		LruCache cache=new LruCache(3,new PerpetualCache());
		cache.putObject("a", 10);
		cache.putObject("b", 10);
		cache.putObject("c", 10);
		cache.getObject("a");
		cache.putObject("d", 10);
		System.out.println(cache.toString());
	}
}


执行结果:
{b=10, c=10, d=10}

测试类2
我们在测试类1的基础上添加一行代码: cache.removeObject(“a”);

public class test2 {
	public static void main(String[] args) {
		LruCache cache=new LruCache(3,new PerpetualCache());
		cache.putObject("a", 10);
		cache.putObject("b", 10);
		cache.putObject("c", 10);
		cache.getObject("a");
		cache.removeObject("a");
		cache.putObject("d", 10);
		System.out.println(cache.toString());
	}
}

执行结果:
{c=10, d=10}

按道理此处结果应该是{b=10,c=10,d=10}而结果却少了一个值,这是为什么呢?
可以肯定的是问题出在remove方法,我们分析一下测试类2代码,设置容量为3,前三个putObject方法往HashMap集合中添加abc的键值对和LinkedHashMap集合中添加abc键,然后调用getObject(“a”)方法,该方法会记录访问顺序.然后紧接着removeObject(“a”)将会删除a的键值对,最后我们putObject(“d”)添加d的键值对.细心的话会发现,我们删除a的时候只删除了a的HashMap中键值对,而没有删除LinkedHashMap中的a键,这样会导致虽然已经删除了a的键值对,但是LinkedHashMap中记录HashMap中依然有三个键值对(实际只有两个),然后我们再添加d的键值对后,会移除最早且最近不经常访问的键值对b,所以结果只有两个键值对

解决办法

@Override
	public Object removeObject(Object key) {
		// TODO Auto-generated method stub
		keyMap.remove(key);//加上删除keyMap的键值对
		return cache.removeObject(key);
	}

先进先出置换算法(FIFO)
结构

  • Cache接口
  • 用PerpetualCache实现类存储数据:HashMap 存数据
  • 用FifoCache 实现类实现缓存算法:LinkedList
import java.util.LinkedList;
public class FifoCache implements Cache{
	private Cache cache;
	private LinkedList<Object> keyOrderlist;
	private int maxCap;
	public FifoCache(int maxCap,Cache cache) {
		this.maxCap=maxCap;
		this.cache=cache;
		keyOrderlist=new LinkedList<Object>();
	}
	@Override
	public void putObject(Object key, Object value) {
		keyOrderlist.add(key);
		if(keyOrderlist.size()>maxCap) {
			Object oldkey = keyOrderlist.removeFirst();
			cache.removeObject(oldkey);
		}
		cache.putObject(key, value);
	}

	@Override
	public Object getObject(Object key) {
		return cache.getObject(key);
	}
	@Override
	public Object removeObject(Object key) {
		// TODO Auto-generated method stub
		return cache.removeObject(key);
	}
	
	public String toString() {
		// TODO Auto-generated method stub
		return cache.toString();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值