上一篇:
LinkedHashMap jdk1.8基础和源码分析
LruCache缓存的核心:LRU(Least Recently Used)最近最少使用算法,即当缓存快要满时,会优先淘汰那些近期最少使用的缓存对象。
LruCache的核心是LinkedHashMap,LinkedHashMap的accessOrder为true,表示按访问顺序进行迭代;建议先看LinkedHashMap jdk1.8基础和源码分析,再来看LruCche就很简单啦。
Android 3.0之前做图片缓存主要用的就是SoftReference,3.0以后虚拟机更倾向于用SoftReference来索引对象,所以LruCache的出现就是为了取代它。
四种引用:
强引用:使用new关键字创建的就是强引用。当一个对象具有强引用,那么垃圾回收器是绝对不会的回收和销毁它的。
软引用:如果一个对象只具有软引用,若内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,才会回收这些对象的内存。但是系统并不知道哪些软引用指向的对象应该被回收,哪些应该被保留。过早地回收对象会导致不必要的工作。
弱引用:在垃圾回收器运行的时候,如果对一个对象的所有引用都是弱引用的话,该对象会被回收。
虚引用:一个只被虚引用持有的对象可能会在任何时候被GC回收。虚引用对对象的生存周期完全没有影响,也无法通过虚引用来获取对象实例,仅仅能在对象被回收时,得到一个系统通知(只能通过是否被加入到ReferenceQueue来判断是否被GC,这也是唯一判断对象是否被GC的途径)。
有点乏味,看源码之前先插个图:
LruCache缓存的插入、查询、删除操作源码解析:
LruCache构造函数
public class LruCache {
private final LinkedHashMap map;
private int size;
private int maxSize;
private int putCount;
private int createCount;
private int evictionCount;
private int hitCount;
private int missCount;
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize; //最多可存储多少个element,构造函数中赋值
this.map = new LinkedHashMap(0, 0.75f, true);
}
}
复制代码
put()插入操作
putCount++,如果map中已经存在key,则返回oldValue,否则返回null;并判断是否需要移除最近最少访问的对象
public final V put(K key, V value) {
if (key == null || value == null) { //不允许空键和空值,LinkedHashMap默认是允许一个空键和N个空值的
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {
putCount++; //putCount加1
size += safeSizeOf(key, value); //size加上element占用的空间
previous = map.put(key, value); //linkedHashMap.put操作
if (previous != null) { //如果map中已经存在key,只是更新value,则减去oldElement占用的空间
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, value); //空方法
}
trimToSize(maxSize);
return previous;
}
//size必须大于0
private int safeSizeOf(K key, V value) {
int result = sizeOf(key, value);
if (result < 0) {
throw new IllegalStateException("Negative size: " + key + "=" + value);
}
return result;
}
//默认实现返回1,用户可自定义
protected int sizeOf(K key, V value) {
return 1;
}
protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
复制代码
trimToSize(maxSize)
在缓存将要满之前,删除最近最少访问的对象,即移除掉map的表头元素
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; //如果size<=maxSize,不需要扩容,跳出循环
}
Map.Entry toEvict = map.eldest(); //取出map的表头head
if (toEvict == null) {
break; //head == null, 无需扩容
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key); //将表头移除掉,linkedHashMap的特性,最近最少访问的对象存储在表头
size -= safeSizeOf(key, value); //size修改
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
复制代码
get(K key)
如果能找到key所对应的value, 则返回value,hitCount++;否则missCount++,返回null
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; //如果能找到key所对应的value, 则返回value,hitCount++;否则missCount++,返回null
}
missCount++;
}
V createdValue = create(key); //create(key)默认返回一个null
if (createdValue == null) {
return null;
}
/** 省略掉部分代码 **/
}
protected V create(K key) {
return null;
}
复制代码
remove(K key)删除操作
public final V remove(K key) {
if (key == null) { //不允许空键
throw new NullPointerException("key == null");
}
V previous;
synchronized (this) {
previous = map.remove(key);
if (previous != null) { //如果存在key,则返回value,更新size;否则没有找到匹配的key,则返回null
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, null); //空方法
}
return previous;
}
复制代码