美文网首页
Glide解析(一) - LruCache

Glide解析(一) - LruCache

作者: 小名坎坎 | 来源:发表于2019-11-21 09:11 被阅读0次
    本文介绍的内容有
    • LruCache算法思想介绍
    • v4包中LruCache中源码解析

    LruCache算法思想介绍

    • LruCache(Least Recently Used)算法的核心思想就是最近最少使用算法
    • 最近最少使用算法
      规则:
      1.限定存储表大小
      2.添加或者使用某个元素式 ,这个元素排序到表头
      3.添加新元素的时候,如果表已满,直接去除表尾元素
      image.png
    v4包中LruCache中源码解析
    • 建议要先简单了解一下LinkedHashMap 数据结构,了解其特点和优势。
      下面是v4包中LruCache这个类的所有代码
    public class LruCache<K, V> {
      // 存放数据的集合 - LinkedHashMap -> 内部结构是封装的双向链表
      private final LinkedHashMap<K, V> map;
      // 当前缓存大小
      private int size;
      // 最大缓存大小
      private int maxSize;
    // 插入元素的次数
      private int putCount;
      // 元素丢失后(根据key没找到value),如果我们重写了oncreate方法并创建成功的次数
      private int createCount;
      // 元素回收的次数
      private int evictionCount;
      // 调用元素的次数 -> 根据key找到value
      private int hitCount;
      // 元素丢失的次数 -> 根据key没找到value
      private int missCount;
        // 初始化 传入最大size
        public LruCache(int maxSize) {
            if (maxSize <= 0) {
                throw new IllegalArgumentException("maxSize <= 0");
            } else {
                this.maxSize = maxSize;
                //创建LinkedHashMap,后面的增删改查操作实际就是对这个map的操作
                // true 按照访问做排序 -> 插入和访问都做排序
                this.map = new LinkedHashMap(0, 0.75F, true);
            }
        }
      // 重置最大size
        public void resize(int maxSize) {
            if (maxSize <= 0) {
                throw new IllegalArgumentException("maxSize <= 0");
            } else {
                synchronized(this) {
                    this.maxSize = maxSize;
                }
                // 到方法中再介绍
                this.trimToSize(maxSize);
            }
        }
        // 根据key查找元素
        @Nullable
        public final V get(@NonNull K key) {
            if (key == null) {
                throw new NullPointerException("key == null");
            } else {
                Object mapValue;
                synchronized(this) {
                    //查找元素
                    mapValue = this.map.get(key);
                    if (mapValue != null) {
                        //不为空则表示访问成功,返回值
                        ++this.hitCount;
                        return mapValue;
                    }
                    // 表示根据key没有找到元素
                    ++this.missCount;
                }
                // 没有找到元素 就去创建元素 ,我们可以重写这个方法
                V createdValue = this.create(key);
                if (createdValue == null) {
                    // 创建失败(没有重写create方法并返回值) -> 返回null
                    return null;
                } else {
                    // 表示创建成功
                    synchronized(this) {
                        // 成功 +1
                        ++this.createCount;
                        // 因为是刚创建出来的,所以要放入map中
                        // 加入后,如果key之前就存在,就返回上次key的value,如果不存在就返回null
                        mapValue = this.map.put(key, createdValue);
                        if (mapValue != null) {
                            //加入旧的value
                            this.map.put(key, mapValue);
                        } else {
                            // 计算大小
                            this.size += this.safeSizeOf(key, createdValue);
                        }
                    }
        
                    if (mapValue != null) {
                        // 如果旧的值存在 ,维持旧的值不变,那么新创建的createdValue就没有用,调用这个方法处理掉
                        this.entryRemoved(false, key, createdValue, mapValue);
                        // 返回旧值
                        return mapValue;
                    } else {
                        // 到方法中再介绍
                        this.trimToSize(this.maxSize);
                        // 返回新创建的值
                        return createdValue;
                    }
                }
            }
        }
        // 添加值
        @Nullable
        public final V put(@NonNull K key, @NonNull V value) {
            if (key != null && value != null) {
                Object previous;
                synchronized(this) {
                  //做了一次添加操作
                    ++this.putCount;
                  // 当前size累加
                    this.size += this.safeSizeOf(key, value);
                    // 查找 返回旧值或者null
                    previous = this.map.put(key, value);
                    if (previous != null) {
                        // 如果旧值存在 ,当前size减去旧值大小
                        this.size -= this.safeSizeOf(key, previous);
                    }
                }
    
                if (previous != null) {
                    // 如果旧值存在 我们要做一些回收操作
                    this.entryRemoved(false, key, previous, value);
                }
                this.trimToSize(this.maxSize);
                return previous;
            } else {
                throw new NullPointerException("key == null || value == null");
            }
        }
        //  这个方法就是通过对当前size和maxSize的循环比较,一直删除元素,直到符合条件
        public void trimToSize(int maxSize) {
            while(true) {
                Object key;
                Object value;
                synchronized(this) {
                    if (this.size < 0 || this.map.isEmpty() && this.size != 0) {
                        throw new IllegalStateException(this.getClass().getName() + ".sizeOf() is reporting inconsistent results!");
                    }
                    // 这个就是循环是否执行的条件
                    if (this.size <= maxSize || this.map.isEmpty()) {
                        return;
                    }
                    // 缓存超出最大值,执行删除元素的操作
                    Entry<K, V> toEvict = (Entry)this.map.entrySet().iterator().next();
                    key = toEvict.getKey();
                    value = toEvict.getValue();
                    this.map.remove(key);
                    this.size -= this.safeSizeOf(key, value);
                    ++this.evictionCount;
                }
    
                this.entryRemoved(true, key, value, (Object)null);
            }
        }
        // 删除操作
        @Nullable
        public final V remove(@NonNull K key) {
            if (key == null) {
                throw new NullPointerException("key == null");
            } else {
                Object previous;
                synchronized(this) {
                    // 根据key移除元素 返回value
                    previous = this.map.remove(key);
                    if (previous != null) {
                        // value不等于null ,重新计算大小
                        this.size -= this.safeSizeOf(key, previous);
                    }
                }
    
                if (previous != null) {
                    // 需要重写的自定义操作
                    this.entryRemoved(false, key, previous, (Object)null);
                }
    
                return previous;
            }
        }
     // 需要重写的自定义操作  比如对旧值的资源回收
        protected void entryRemoved(boolean evicted, @NonNull K key, @NonNull V oldValue, @Nullable V newValue) {
        }
        // 重写方法  查找不到值的时候 可以按照这个来创建
        @Nullable
        protected V create(@NonNull K key) {
            return null;
        }
        // 返回元素大小
        private int safeSizeOf(K key, V value) {
            // 返回元素实际大小
            int result = this.sizeOf(key, value);
            if (result < 0) {
                throw new IllegalStateException("Negative size: " + key + "=" + value);
            } else {
                return result;
            }
        }
        // 可重写 返回元素实际大小
        protected int sizeOf(@NonNull K key, @NonNull V value) {
            return 1;
        }
    
        public final void evictAll() {
            this.trimToSize(-1);
        }
    
        public final synchronized int size() {
            return this.size;
        }
    
        public final synchronized int maxSize() {
            return this.maxSize;
        }
    
        public final synchronized int hitCount() {
            return this.hitCount;
        }
    
        public final synchronized int missCount() {
            return this.missCount;
        }
    
        public final synchronized int createCount() {
            return this.createCount;
        }
    
        public final synchronized int putCount() {
            return this.putCount;
        }
    
        public final synchronized int evictionCount() {
            return this.evictionCount;
        }
    
        public final synchronized Map<K, V> snapshot() {
            return new LinkedHashMap(this.map);
        }
    
        public final synchronized String toString() {
            int accesses = this.hitCount + this.missCount;
            int hitPercent = accesses != 0 ? 100 * this.hitCount / accesses : 0;
            return String.format(Locale.US, "LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]", this.maxSize, this.hitCount, this.missCount, hitPercent);
        }
    }
    

    相关文章

      网友评论

          本文标题:Glide解析(一) - LruCache

          本文链接:https://www.haomeiwen.com/subject/bvkeaqtx.html