LRUCache策略

本文深入解析LRUCache的实现原理及应用,介绍如何利用LinkedHashMap实现最近最少使用的缓存策略,包括bitmap图片缓存等场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


LRUCache:最近最少使用(Least Recently Used)缓存,可用于bitmap 的图片缓存。


具体策略就是:以一个LinkedHashMap来存放元素,LinkedHashMap设置以访问时间存储。在每次存的时候,判断如果size超过设定的最大尺寸maxSize,就删除掉最不常用的元素,直到满足不大于maxSize。

1)对于bitmap,可以设maxSize=4M,通过重写sizeOf方法返回bitmap的真正字节大小。

2)可以重写create方法(默认实现return null),创建出key对应的value对象,这样每次get的时候,如果元素不存在,就通过create创建,并将创建的元素加入map,此时如果产生了冲突,就用旧的元素替换掉创建的元素。然后调整map的size大小。



源码说明如下:



初始化LinkedHashMap,传入的第三个参数true。表示我们在访问获取的时候,会根据时间进行排序。

public LruCache(int maxSize) {
    ...
    this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
  }



public final V get(K key) {//通过key来获取存储的数据
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        V mapValue;
        synchronized (this) {
            mapValue = map.get(key);//其实是通过LinkedHashMap来获取的
            if (mapValue != null) {
                hitCount++; //这里时在记录每次获取数据成功的次数
                return mapValue;
            }
            missCount++;//这里记录获取数据失败的次数
        }
  

        V createdValue = create(key);//如果当前没有这个数据,则调用create创建
        if (createdValue == null) {
            return null;
        }

        synchronized (this) {
            createCount++;//更新自己创建的数量
            mapValue = map.put(key, createdValue);//将新创建的数据加入到LinkedHashMap里面

            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);//调用entryRemoved通知已经清理掉了一个数据
            return mapValue;
        } else {
            trimToSize(maxSize);//检测是否已经满了
            return createdValue;
        }
    }





调整map大小,判断是否需要移除

  public void trimToSize(int maxSize) {
        while (true) {//一个死循环:直到当前LruCache没有满才会跳出这个循环
            K key;
            V value;
            synchronized (this) {
                if (size < 0 || (map.isEmpty() && size != 0)) {//异常错误检测:当前已经缓存的数据数量不能为负数,并且没有数据的时候其数据数量不能大于0
                    throw new IllegalStateException(getClass().getName()
                            + ".sizeOf() is reporting inconsistent results!");
                }

                if (size <= maxSize) {//如果已经缓存的数据数量小于最大容量(没有满),则跳出循环
                    break;
                }

                Map.Entry<K, V> toEvict = map.eldest();//通过LinkedHashMap来获取最不常用的一个键值对数据
                if (toEvict == null) {
                    break;
                }

                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);  //删除这个数据
                size -= safeSizeOf(key, value); //获取这个删除的键值对数据所占用的容量(有可能是1,也有可能是计算的图片占用的内存,也有可能是其他)
                evictionCount++;
            }

            entryRemoved(true, key, value, null); //回调用entryRemoved,一般用于通知客户端,这个键值对数据已经被清理出LruCache了
        }
    }	


可供重写的函数

protected V create(K key) {
    return null;
}


  protected int sizeOf(K key, V value) {
        return 1;
    }

protected V create(K key) {
    return null;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值