热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

javacache详解,Java容器解析系列(17)LruCache详解

在之前讲LinkedHashMap的时候,我们说起可以用来实现LRU(leastrecentused)算法,接下来我看一下其中的一个具体实现-----androidsdk中的Lru

在之前讲LinkedHashMap的时候,我们说起可以用来实现LRU(least recent used)算法,接下来我看一下其中的一个具体实现-----android sdk 中的LruCache.

talk is cheap, I am gonna show you something really expensive.

package android.util;// 该类是从Android sdk 中摘录

public class LruCache {

private final LinkedHashMap map;// 这里的 LinkedHashMap 为 android.jar 中的类,与jdk中的有所区别,这里不做区分

private int size;// 当前 cache 的大小

private int maxSize;// cache 最大容量

private int putCount;// put() 调用的次数

private int createCount;// get()未命中,成功构建新 key:value 的次数

private int evictionCount;// 因cache大小超过容量限制,将 key:value 从 cache 中驱逐的次数

private int hitCount;// get()命中的次数

private int missCount;// get()未命中的次数

// 构造时设置最大容量

public LruCache(int maxSize) {

if (maxSize <&#61; 0) {

throw new IllegalArgumentException("maxSize <&#61; 0");

}

this.maxSize &#61; maxSize;

// 这里传入的 LinkedHashMap 的 accessOrder 为true,表示 其中的链表中的结点顺序为 "按访问顺序"

this.map &#61; new LinkedHashMap(0, 0.75f, true);

}

// 重新设置 cache 最大容量

public void resize(int maxSize) {

if (maxSize <&#61; 0) {

throw new IllegalArgumentException("maxSize <&#61; 0");

}

synchronized (this) {

this.maxSize &#61; maxSize;

}

trimToSize(maxSize);

}

public final V get(K key) {

if (key &#61;&#61; null) {

throw new NullPointerException("key &#61;&#61; null");

}

V mapValue;

synchronized (this) {// 同步访问

mapValue &#61; map.get(key);

if (mapValue !&#61; null) {

hitCount&#43;&#43;;// 命中次数 &#43; 1

return mapValue;

}

missCount&#43;&#43;;// 未命中次数 &#43; 1

}

V createdValue &#61; create(key);// 通过 key 构建一个value(比如从文件中读入value)

if (createdValue &#61;&#61; null) {// 创建失败

return null;

}

synchronized (this) {

createCount&#43;&#43;;// 构建 value 成功次数 &#43; 1

mapValue &#61; map.put(key, createdValue);// 添加到 LinkedHashMap 中

if (mapValue !&#61; null) {

// LinkedHashMap 原来有该key的值(在构建value的时候,被其他线程添加进去的),这里重新把原来的值放进去,cache大小没有增加

map.put(key, mapValue);

} else {

size &#43;&#61; safeSizeOf(key, createdValue);// cache 大小增加

}

}

if (mapValue !&#61; null) {

entryRemoved(false, key, createdValue, mapValue);

return mapValue;

} else {

trimToSize(maxSize);// 大小增加了,保证在最大容量范围内

return createdValue;

}

}

public final V put(K key, V value) {

if (key &#61;&#61; null || value &#61;&#61; null) {

throw new NullPointerException("key &#61;&#61; null || value &#61;&#61; null");

}

V previous;

synchronized (this) {

putCount&#43;&#43;;// put 次数

size &#43;&#61; safeSizeOf(key, value);

previous &#61; map.put(key, value);

if (previous !&#61; null) {

size -&#61; safeSizeOf(key, previous);// 替换已有的value

}

}

if (previous !&#61; null) {

entryRemoved(false, key, previous, value);

}

trimToSize(maxSize);

return previous;

}

// 移除LRU键值对,保证 cache 的大小在 maxSize 范围内

public void trimToSize(int maxSize) {

while (true) {

K key;

V value;

synchronized (this) {

if (size <0 || (map.isEmpty() && size !&#61; 0)) {

throw new IllegalStateException(getClass().getName()

&#43; ".sizeOf() is reporting inconsistent results!");

}

if (size <&#61; maxSize) {

break;

}

Map.Entry toEvict &#61; map.eldest();// 最老的结点,返回head结点,也即 LRU结点

if (toEvict &#61;&#61; null) {// 没有可以删除的key:value了

break;

}

key &#61; toEvict.getKey();

value &#61; toEvict.getValue();

map.remove(key);

size -&#61; safeSizeOf(key, value);// 大小降低

evictionCount&#43;&#43;;// 驱逐次数 &#43; 1

}

entryRemoved(true, key, value, null);

}

}

public final V remove(K key) {

if (key &#61;&#61; null) {

throw new NullPointerException("key &#61;&#61; null");

}

V previous;

synchronized (this) {

previous &#61; map.remove(key);// 通过 LinkedHashMap 移除

if (previous !&#61; null) {

size -&#61; safeSizeOf(key, previous);// cache总大小降低

}

}

if (previous !&#61; null) {

entryRemoved(false, key, previous, null);

}

return previous;

}

// key:oldValue 被 移除 或 驱逐 时回调

protected void entryRemoved(boolean evicted/*是否是被驱逐(因cache大小超过容量限制被删除)*/,

K key, V oldValue, V newValue) {

}

// 根据指定 key,构建 value

protected V create(K key) {

return null;

}

private int safeSizeOf(K key, V value) {

int result &#61; sizeOf(key, value);

if (result <0) {

throw new IllegalStateException("Negative size: " &#43; key &#43; "&#61;" &#43; value);

}

return result;

}

// key:value 键值对大小,用于计算cache大小

// 可根据情况自定义,默认为 1

// 该 key:value 在 cache 中时大小不应该变化

protected int sizeOf(K key, V value) {

return 1;

}

public final void evictAll() {

trimToSize(-1); // -1 will evict 0-sized elements

}

// 各种方法,返回成员变量,省略

public synchronized final Map snapshot() {

return new LinkedHashMap(map);

}

&#64;Override

public synchronized final String toString() {

int accesses &#61; hitCount &#43; missCount;

int hitPercent &#61; accesses !&#61; 0 ? (100 * hitCount / accesses) : 0;

return String.format("LruCache[maxSize&#61;%d,hits&#61;%d,misses&#61;%d,hitRate&#61;%d%%]",

maxSize, hitCount, missCount, hitPercent);

}

}



推荐阅读
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 本文介绍了brain的意思、读音、翻译、用法、发音、词组、同反义词等内容,以及脑新东方在线英语词典的相关信息。还包括了brain的词汇搭配、形容词和名词的用法,以及与brain相关的短语和词组。此外,还介绍了与brain相关的医学术语和智囊团等相关内容。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 标题: ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
author-avatar
时尚经典语录覀---
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有