基于继承LinkedHashMap实现LRU算法:
-
LinkedHashMap
存储结构: 链表+散列表
存储算法:LRU+哈希算法 -
LinkedHashMap 特性
记录元素添加顺序,访问数据
线程不安全 -
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();
}
}