android开发LruCache原理理解与源码实现方式
原创
©著作权归作者所有:来自51CTO博客作者yongfengnice的原创作品,请联系作者获取转载授权,否则将追究法律责任
- 简写:Least Recently Used
- 即最近最少使用,是一种调度算法或者说淘汰机制。就是每个Item都有一个访问字段t,记录自上次被访问的时间,当需要移除时选择移除t值最大的Item。
- androidx.collection.LruCache实现
- 基层依赖LinkedHashMap。而LinkedHashMap是一个双向链表。
public LruCache(int maxSize) {//最大缓存大小
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
//accessOrder为false,表示map元素顺序跟随插入顺序,默认值。
//accessOrder为true,表示map元素顺序跟随访问顺序变化。即一个元素被访问时,同时调整其位置将其放到最后,刚好符合lru原则。
public final V put(@NonNull K key, @NonNull V value) {
V previous;
synchronized (this) {//线程安全的
size += safeSizeOf(key, value);
//在key位置上放新值value,返回key位置之前的旧值
previous = map.put(key, value);
if (previous != null) {//减去旧值的size
size -= safeSizeOf(key, previous);
}
}
//如果旧值不为空,则回调entryRemoved方法
if (previous != null) {
entryRemoved(false, key, previous, value);
}
trimToSize(maxSize);//size变化了,检查要不要剔除最老元素
return previous;
}
public final V get(@NonNull K key) {
V mapValue;
synchronized (this) {
//注意:get方法不仅取值,如果取到了还会更新该元素位置
//即移到链表最后位置tail,因为之前参数accessOrder为true
mapValue = map.get(key);
if (mapValue != null) {
return mapValue;//找到了直接返回
}
}
V createdValue = create(key);//找不到就创建新的
if (createdValue == null) {
return null;
}
synchronized (this) {
mapValue = map.put(key, createdValue);
if (mapValue != null) {//基本为null,除非并发
map.put(key, mapValue);
} else {//size变化,后面调用trimToSize重新检查调整
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {//并发导致刚好已经有旧值了
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
trimToSize(maxSize);
return createdValue;
}
}
public void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
//如果size没有达到最大缓存maxSize或者map为空,直接返回了,不需要移除操作
if (size <= maxSize || map.isEmpty()) {
break;
}
//获取第一个元素,也就是最老最久没被使用的元素,将它移除。还记得get时会刷新get到元素的位置吧??
Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);//移除后size减少
}
entryRemoved(true, key, value, null);
}
}