首页 > 编程语言 >LruCache源码解析

LruCache源码解析

时间:2024-04-28 21:57:52浏览次数:28  
标签:map 解析 last value 源码 mapValue key null LruCache

最近被问到LruCache原理一直觉得很简单的东西猛然一想,卧槽忘了,赶紧翻开源码瞧瞧!



1、首先构造lrucache的时候会新建一个linkedHashMap来作为存储容器
 public LruCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
    }

 

2、构造LinkedHashMap的时候传入了一个true作为accessOrder的值

 public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

3、当LruCache调用get的时候会调用LinkedHashMap的方法

public final V get(K key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        V mapValue;
        synchronized (this) {
            mapValue = map.get(key);//这里会调用LinkedHashMap的get方法
            if (mapValue != null) {
                hitCount++;
                return mapValue;
            }
            missCount++;
        }

        /*
         * Attempt to create a value. This may take a long time, and the map
         * may be different when create() returns. If a conflicting value was
         * added to the map while create() was working, we leave that value in
         * the map and release the created value.
         */

        V createdValue = create(key);
        if (createdValue == null) {
            return null;
        }

        synchronized (this) {
            createCount++;
            mapValue = map.put(key, createdValue);

            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);
            return mapValue;
        } else {
            trimToSize(maxSize);
            return createdValue;
        }
    }

4、这是LinkedHashMap的get方法

public V get(Object key) {
        Node<K,V> e;
        if ((e = getNode(key)) == null)
            return null;
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
    }

5、因为前面传入的accessOrder为true所以一定会调用afterNodeAccess方法

void afterNodeAccess(Node<K,V> e) { // move node to last
        LinkedHashMapEntry<K,V> last;
        if (accessOrder && (last = tail) != e) {
            LinkedHashMapEntry<K,V> p =
                (LinkedHashMapEntry<K,V>)e, b = p.before, a = p.after;
            p.after = null;
            if (b == null)
                head = a;
            else
                b.after = a;
            if (a != null)
                a.before = b;
            else
                last = b;
            if (last == null)
                head = p;
            else {
                p.before = last;
                last.after = p;
            }
            tail = p;
            ++modCount;
        }
    }

6、afterNodeAccess方法直接将被访问的元素放到了队列尾部并返回,然后lruCache进行重新trimtoSize的时候直接将移除的使map.eldest()返回的元素

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;
                }

                Map.Entry<K, V> toEvict = map.eldest();
                if (toEvict == null) {
                    break;
                }

                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);
                size -= safeSizeOf(key, value);
                evictionCount++;
            }

            entryRemoved(true, key, value, null);
        }
    }

7、LinkedHashMap eldest()方法返回的直接是头节点,也就是最近使用的元素都会到LinkedHashMap的末尾节点,而头节点聚集的都是最久未使用元素

public Map.Entry<K, V> eldest() {
        return head;
    }

这就实现了缓存策略最近使用优先级最高

 

 

标签:map,解析,last,value,源码,mapValue,key,null,LruCache
From: https://www.cnblogs.com/laogonggong/p/18164569

相关文章

  • JDK源码分析-HashSet
    概述HashSet是Java集合框架中非常重要的一个类,它实现了Set接口,不允许出现重复元素,并且元素是无序的。HashSet的底层实现主要依赖于HashMap,通过HashMap来存储元素。如果想要了解HashMap,可以查看后续文章。类图从以上类图可以看到,HashSet实现了三个接口,继承了一个抽象类:Serial......
  • RocketMQ生产者启动源码
    核心代码初始化Default生产者DefaultMQProducerproducer=newDefaultMQProducer(PRODUCER_GROUP);设置NameAddr地址producer.setNamesrvAddr(DEFAULT_NAMESRVADDR);producer.start();分析newDefaultMQProducer(PRODUCER_GROUP)publicDefaultMQProducer(finalStringp......
  • 探索项目管理系统:解析五大功能,洞悉项目成功的关键
    项目管理新手往往喜欢埋头苦干,殊不知优秀的项目经理已经熟练运用项目管理系统,让项目规划条理清晰。项目管理系统具备的功能,好用的项目管理系统都有这5大功能。分别是项目WBS分解、项目图表和报表、工时管理、团队协作、任务流程自动化。一、项目WBS分解1.什么是项目WBS分解?从......
  • 后端每日一题 2:DNS 解析过程
    本文首发于公众号:腐烂的橘子本文梗概:DNS是什么,有什么作用一条DNS记录是什么样的DNS域名解析原理DNS服务器如何抵御攻击DNS是什么,有什么作用DNS(DomainNameSystem)是一种应用层协议,用于映射域名和ip地址。为什么要做映射呢?就像可以用身份证号来对应一个人,也可......
  • DRF源码汇总
    DRF源码汇总【一】三大认证【1】认证【2】权限【3】频率【3.1】SimpleRateThrottle源码分析【二】JWT【1】simple-jwt【1.1】登录【1.2】认证......
  • ubuntu18源码安装postgresql15.2数据库
    由于官方的源只能安装到pg10这个版本,整了好一会没有成功就改为源码安装了。下载源代码源码并解压wgethttps://ftp.postgresql.org/pub/source/v15.2/postgresql-15.2.tar.gztar-xfpostgresql-15.2.tar.gzcdpostgresql-15.2/安装C++相关开发库和编译工具aptinst......
  • 初中中考阅读理解难题一网打尽!句子结构深度解析+答案揭秘,助你轻松冲刺高分!-012
    PDF格式公众号回复关键字:ZKYDT012原文1Richardfoundthebirdintheforest,didn’the?解析1Richard,found发现了,thebird这只鸟,intheforest在森林里,didn’the?不是吗理查德在森林里发现了这只鸟,不是吗?2Hesawastrangebirdinabush.他在灌木丛......
  • 探索 DTD 在 XML 中的作用及解析:深入理解文档类型定义
    DTD是文档类型定义(DocumentTypeDefinition)的缩写。DTD定义了XML文档的结构以及合法的元素和属性。为什么使用DTD通过使用DTD,独立的团体可以就数据交换的标准DTD达成一致。应用程序可以使用DTD来验证XML数据的有效性。内部DTD声明如果DTD在XML文件内声......
  • GIS中XYZ瓦片的加载流程解析与实现
    1.什么是XYZ瓦片XYZ瓦片是一种在线地图数据格式,常见的地图底图如Google、OpenStreetMap等互联网的瓦片地图服务,都是XYZ瓦片,严格来说是ZXY规范的地图瓦片ZXY规范的地图瓦片规则如下:将地图全幅显示时的图片从左上角开始,往下和往右进行切割,切割的大小默认为256*256像素,左上角的......
  • JDK源码分析-Vector
    概述Vector是Java集合中线程安全的动态数组,它也可以根据需要进行扩容和缩容,与ArrayList类似。但有一个重要的区别,Vector是同步的,也就是它的操作是线程安全的,在某些特定场景下是可以保证线程安全的,但同时也会带来性能损耗,因此在单线程环境通常还是推荐使用ArrayList。类图......