LruCache代码只有300多行,看起来很简单
0. 属性
//主要的存储成员变量
private final LinkedHashMap<K, V> map;
//当前容量
private int size;
//最大的值
private int maxSize;
//put的次数
private int putCount;
//create的次数
private int createCount;
//回收次数
private int evictionCount;
//命中次数
private int hitCount;
//丢失的次数
private int missCount;
关于LinkedHashMap,我们已经讲过了,这里就不再叙述了
1. 方法
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);
}
- initialCapacity 用于初始化该 LinkedHashMap 的大小。
- loadFactor(负载因子)这个LinkedHashMap的父类 HashMap 里的构造参数,涉及到扩容问题,比如 HashMap 的最大容量是100,那么这里设置0.75f的话,到75的时候就会扩容。
- accessOrder,这个参数是排序模式,true表示在访问的时候进行排序( LruCache 核心工作原理就在此),false表示在插入的时才排序。
1.1 put方法
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {
putCount++;
//如果部重写,那么这个容量就是1
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {
//如果已经存在这个值了,那么就要删除容量
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
// 留给子类重写的方法
entryRemoved(false, key, previous, value);
}
//调整缓存大小(关键方法)
trimToSize(maxSize);
return previous;
}
1.2 trimToSize方法
public void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
+ ".sizeOf() is reporting inconsistent results!");
}
if (size <= maxSize) {
break;
}
Map.Entry<K, V> toEvict = map.eldest();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
该方法就是循环查找如果当前的大小超过最大的值,那么就删除最旧的节点,回收次数+1,直到size小于maxSize为止。
1.3 get()方法
public final V get(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
V createdValue = create(key);
if (createdValue == null) {
return null;
}
synchronized (this) {
createCount++;
mapValue = map.put(key, createdValue);
if (mapValue != null) {
// There was a conflict so undo that last put
map.put(key, mapValue);
} else {
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
trimToSize(maxSize);
return createdValue;
}
}
get方法流程是:
- 根据key从map中拿数据,如果拿到数据那么就命中次数+1,然后退出;
- 如果没有拿到map中数据,那么miss+1,然后创建value,LruCache中数据是null,所以会直接返回null;
- 如果子类重写了create的方法,那么createCount++,并且以这个key保存到map中,如果map中存在了key,那么重新put上一次的value,如果不为空,那么size变大。
LruCahe先分析到这里!
网友评论