最近在学习Glide源码用到了LruCache,LRU (Least Recently Used) 的意思就是近期最少使用算法,它的核心思想就是会优先淘汰那些近期最少使用的缓存对象。
//有序map,此处用到了基于访问的排序
private final LinkedHashMap<K, V> map;
//当前缓存容量
private int size;
//最大缓存容量
private int maxSize;
//put次数
private int putCount;
//子类重新create()方法有效,当根据Key找不到对应的Value,创建Value的次数
private int createCount;
//回收资源的次数
private int evictionCount;
//命中(根据Key获取到Value)的次数
private int hitCount;
//错误(根据Key找不到Value)的次数
private int missCount;
这些是LruCache中定义的全局变量,理解后这个类就变得非常易懂。
我们先来看一下构造方法,这里包含了LruCache实现的主要原理
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
} else {
this.maxSize = maxSize;
this.map = new LinkedHashMap(0, 0.75F, true);
}
}
LinkedHashMap构造方法
public LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder)
参数说明:
initialCapacity 初始容量大小,使用无参构造方法时,此值默认是16
loadFactor 加载因子,使用无参构造方法时,此值默认是 0.75f
accessOrder false: 基于插入顺序 true: 基于访问顺序(最近访问的value放在LinkedHashMap的最后)
map.put()方法说明:
Map里的put方法,如果key值不存在,则返回值是null,如果key存在,则会返回原先被替换掉的value值.(当然map中的key和value都允许是null)
上面是我们的准备工作,下面列举了两个关键的方法予以说明,都添加详细的注释
put():
public final V put(@NonNull K key, @NonNull V value) {
if (key != null && value != null) {
Object previous;
synchronized(this) {
++this.putCount;
//重新计算缓存的大小,需要重写sizeOf()否则大小均为1
this.size += this.safeSizeOf(key, value);
previous = this.map.put(key, value);
if (previous != null) {
//说明map中已经存在相同的key,previous为map中key之前对应的value。此处减去previous的大小。相当于更新了key对应的value
this.size -= this.safeSizeOf(key, previous);
}
}
if (previous != null) {
//子类重写,删除previous的回调
this.entryRemoved(false, key, previous, value);
}
//重新计算混存大小,如果混存数据超出maxSize则删除map头部的value
this.trimToSize(this.maxSize);
return previous;
} else {
throw new NullPointerException("key == null || value == null");
}
}
get():
public final V get(@NonNull K key) {
if (key == null) {
throw new NullPointerException("key == null");
} else {
Object mapValue;
synchronized(this) {
//根据key从map中拿数据
mapValue = this.map.get(key);
if (mapValue != null) {
//如果拿到数据那么就命中次数+1,然后退出
++this.hitCount;
return mapValue;
}
//如果没有拿到map中数据,那么miss+1
++this.missCount;
}
//调用子类创建value,
V createdValue = this.create(key);
//LruCache中数据是null,所以会直接返回null
if (createdValue == null) {
return null;
} else {
synchronized(this) {
++this.createCount;
//以这个key保存到map中
mapValue = this.map.put(key, createdValue);
if (mapValue != null) {
//map中已经存在了key,那么重新put上一次的value
this.map.put(key, mapValue);
} else {
//如果不存在相同key,重新计算大小
this.size += this.safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
//map中已经存在了key,调用子类entryRemoved()
this.entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
this.trimToSize(this.maxSize);
return createdValue;
}
}
}
}