IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> LruCache源码解析 -> 正文阅读

[移动开发]LruCache源码解析

lrucache,最近最少使用缓存策略,源码其实很简单,没有多少行。下面我们分两个部分来解析:

第一部分:如何使用

    /**
     * 存储的key类型
     * 存储的value类型
     * 设置最大存储容量
     * 计算每个存储内容大小
     */
    LruCache<String, Bitmap> bitmapLruCache=new LruCache<String, Bitmap>(1024*1024){
        @Override
        protected int sizeOf(String key, Bitmap value) {
            return value.getByteCount();
        }
    };
    
    public void useLruCache(){
        //保存数据
        bitmapLruCache.put("111",bitmap);
        //获取数据
        Bitmap bitmap = bitmapLruCache.get("111");
        if(null!=bitmap){
            //使用数据
        }
    }

第二部分:源码分析

首先我们先来翻译一下LruCache源码头文件内容:

* A cache that holds strong references to a limited number of values. Each time
 * a value is accessed, it is moved to the head of a queue. When a value is
 * added to a full cache, the value at the end of that queue is evicted and may
 * become eligible for garbage collection.
   //这个类是一个强引用的有一定大小限制的缓存类。每次访问这个存储的内容,他都将被放到队列头部
   //(这里应该是表述错误,应该是放到队列尾部).如果一个内容想要被添加进一个容量已经满的缓存中
   //那么处于缓存队列尾部的内容将会被移除队列,并且被垃圾回收器回收。
 *
 * <p>If your cached values hold resources that need to be explicitly released,
 * override {@link #entryRemoved}.
   //如果缓存持有的内容需要被释放掉,那么需要重写entryRemoved方法。
 *
 * <p>If a cache miss should be computed on demand for the corresponding keys,
 * override {@link #create}. This simplifies the calling code, allowing it to
 * assume a value will always be returned, even when there's a cache miss.
   //如果一个被移除的缓存要求重新回到缓存队列中,那么可以重新create方法。这个方法,允许一个
   //将要被回收的内容被重新恢复。
 *
 * <p>By default, the cache size is measured in the number of entries. Override
 * {@link #sizeOf} to size the cache in different units. For example, this cache
 * is limited to 4MiB of bitmaps:
  //通常情况下,缓存内容的大小根据缓存条目数量来衡量。重新sizeOf方法,可以改变计算缓存内容的方 
  //法。例如,缓存内容控制在4M以内的缓存bitmap的实例:
 * <pre>   {@code
 *   int cacheSize = 4 * 1024 * 1024; // 4MiB
 *   LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
 *       protected int sizeOf(String key, Bitmap value) {
 *           return value.getByteCount();
 *       }
 *   }}</pre>
 *
 * <p>This class is thread-safe. Perform multiple cache operations atomically by
 * synchronizing on the cache: <pre>   {@code
 *   synchronized (cache) {
 *     if (cache.get(key) == null) {
 *         cache.put(key, value);
 *     }
 *   }}</pre>
 *   //这个类是线程安全的。
 * <p>This class does not allow null to be used as a key or value. A return
 * value of null from {@link #get}, {@link #put} or {@link #remove} is
 * unambiguous: the key was not in the cache.
     //这个类不允许存储的key或者value为null。如果以key保存的内容不存在,那么get put remove方法
    //将会返回null

通过头文件,我们可以知道:

1.lrucache是线程安全的,关键操作都是枷锁的

2.不允许key或者value为null去缓存数据

3.sizeof方法应该说是必须要重写的,用来计算存储内容大小。如果被缓存的内容移除时需要释放掉,那么entryRemoved?方法中可以释放。当然create方法可以让那些被释放的内容起死回生。

4.上面给出了一个如何使用的示例。

源码分析:

1.创建

 /**
     * @param maxSize for caches that do not override {@link #sizeOf}, this is
     *     the maximum number of entries in the cache. For all other caches,
     *     this is the maximum sum of the sizes of the entries in this cache.
     */
    public LruCache(int maxSize) {
        this.maxSize = maxSize;
        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
    }

设置最大缓存容量,初始化LinkedHashMap,双向链表保存数据,特别注意最后一个参数是true,表示如果链表节点每次被访问则会重新排序,将访问的节点放入到链表尾部。

2.存储数据

public final V put(K key, V value) {
        V previous;
        synchronized (this) {
            putCount++;
            //获取插入内容大小
            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;
    }

计算存储内容大小,放入链表中,如果之前链表中有内容,则计算新内容和老内容大小差值,并且调用entryRemoved方法,我们可以在这个方法中释放旧内容。计算缓存内容是否超过设定最大值。trimToSize?方法我们看一下:

private void trimToSize(int maxSize) {
        //只要目前缓存内容大小超过最大值,则不停的删除头节点
        while (true) {
            K key;
            V value;
            synchronized (this) {
                //如果内容大小小于最大值,则退出循环
                if (size <= maxSize) {
                    break;
                }
                //获取头节点
                Map.Entry<K, V> toEvict = map.eldest();
                if (toEvict == null) {
                    break;
                }
                // END LAYOUTLIB CHANGE

                if (toEvict == null) {
                    break;
                }
                //删除头结点
                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);
                size -= safeSizeOf(key, value);
                evictionCount++;
            }
            entryRemoved(true, key, value, null);
        }
    }

只要目前存储的内容大于设定的最大值,则将链表的头节点数据删除掉,直到小于设置的最大值。

3.获取数据:

public final V get(K key) {
        V mapValue;
        synchronized (this) {
            //获取内容,同时将此节点放到到链表尾部
            mapValue = map.get(key);
            if (mapValue != null) {
                hitCount++;
                return mapValue;
            }
        }
    }

此方法会获取到节点内容,同时会将节点重新排序,放入到链表尾部。

我们可以看到,lrucache充分利用了linkhashmap源码只要节点被访问则会重新排序,将访问节点放到最后节点的特点。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-03-12 17:41:04  更:2022-03-12 17:42:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 19:03:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码