LruCache源码解析 缓存策略分析

最近在学习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;
            }
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值