【源代码】LruCache源代码剖析
上一篇分析了LinkedHashMap源代码,这个Map集合除了拥有HashMap的大部分特性之外。还拥有链表的特点,即能够保持遍历顺序与插入顺序一致。
另外。当我们将accessOrder设置为true时。能够使遍历顺序和訪问顺序一致,其内部双向链表将会依照最近最少訪问到最近最多訪问的顺序排列Entry对象,这能够用来做缓存。
private final LinkedHashMap<K, V> map;
/** Size of this cache in units. Not necessarily the number of elements. */
private int size;//当前大小
private int maxSize;//最大容量
private int putCount;//put次数
private int createCount;//create次数
private int evictionCount;//回收次数
private int hitCount;//命中次数
private int missCount;//丢失次数
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);
}
首先是put方法:
public final V put(K key, V value) {
if (key == null || value == null) {//键值不同意为空
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {//线程安全
putCount++;
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {//之前已经插入过同样的key
size -= safeSizeOf(key, previous);//那么减去该entry的容量,由于发生覆盖
}
}
if (previous != null) {
entryRemoved(false, key, previous, value);//这种方法默认空实现
}
trimToSize(maxSize);//若容量超过maxsize,将会删除近期非常少訪问的entry
return previous;
}
除此之外,put操作被加锁了,所以是线程安全的!
public void trimToSize(int maxSize) {
while (true) {//不断删除linkedHashMap头部entry,也就是近期最少訪问的条目。直到size小于最大容量
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 || map.isEmpty()) {//直到容量小于最大容量为止
break;
}
Map.Entry<K, V> toEvict = map.entrySet().iterator().next();//指向链表头
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);//删除最少訪问的entry
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
private 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 = null;
for (Map.Entry<K, V> entry : map.entrySet()) {
toEvict = entry;
}
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
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++;//命中次数加1
return mapValue;//返回value
}
missCount++;//未命中
}
V createdValue = create(key);//默认返回为false
if (createdValue == null) {
return null;
}
synchronized (this) {
createCount++;//假设创建成功,那么create次数加1
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;
}
}
public final V remove(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V previous;
synchronized (this) {
previous = map.remove(key);//调用LinkedHashMap的remove方法
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, null);
}
return previous;//返回value
}
sizeof:这种方法用于计算每一个条目的大小,子类必须得复写这个类。
protected int sizeOf(K key, V value) {//用于计算每一个条目的大小
return 1;
}
snapshot方法,返回当前缓存中全部的条目集合
public synchronized final Map<K, V> snapshot() {
return new LinkedHashMap<K, V>(map);
}
【源代码】LruCache源代码剖析的更多相关文章
- android之LruCache源代码解析
移动设备开发中,因为移动设备(手机等)的内存有限,所以使用有效的缓存技术是必要的.android提供来一个缓存工具类LruCache,开发中我们会经经常使用到,以下来他是怎样实现的. 在package ...
- 图像库---Image Datasets---OpenSift源代码---openSurf源代码
1.Computer Vision Datasets on the web http://www.cvpapers.com/datasets.html 2.Dataset Reference http ...
- MINA2 源代码学习--源代码结构梳理
一.mina总体框架与案例: 1.总体结构图: 简述:以上是一张来自网上比較经典的图,总体上揭示了mina的结构,当中IoService包括clientIoConnector和服务端IoAccepto ...
- 【Java集合源代码剖析】TreeMap源代码剖析
转载请注明出处:http://blog.csdn.net/ns_code/article/details/36421085 前言 本文不打算延续前几篇的风格(对全部的源代码加入凝视),由于要理解透Tr ...
- Java To CSharp源代码转换
前言 开发环境 客户端:Unity3D开发(C#) 服务器:Java (基于Java7) 日 期:2016年09月 需求说明 部分服务器的部分逻辑功能在客户端实现一遍,可以简单的理解为服务器的部分 ...
- Apple II DOS 源代码发布
加州山景城的计算机历史博物馆不仅仅展示硬件,还展示软件.博物馆此前已发布了著名软件MacPaint .Photoshop和APL的源代码,现在它公开了1978年的Apple II DOS源代码.源代码 ...
- 在Android中调用C#写的WebService(附源代码)
由于项目中要使用Android调用C#写的WebService,于是便有了这篇文章.在学习的过程中,发现在C#中直接调用WebService方便得多,直接添加一个引用,便可以直接使用将WebServi ...
- 1、android源代码下载与跟踪
学习Android源代码的目的 理解Android API查找API(Activity.Content Provider等) 高级应用开发(ROM定制) 在不同平台下载Android源代码 W ...
- Ubuntu10.04下载并编译Android4.3源代码
注:转载或引用请标明出处 http://blog.csdn.net/luzhenrong45/article/details/9719433 去年用Ubuntu10.10成功下载并编译Andro ...
随机推荐
- MIP启发式求解:局部搜索 (local search)
*本文主要记录和分享学习到的知识,算不上原创. *参考文献见链接. 本文讲述的是求解MIP问题的启发式算法. 启发式算法的目的在于短时间内获得较优解. 个人认为局部搜索(local search)几乎 ...
- 【javascript面试题】之一
1.求y和z的值是多少?<script type="text/javascript">var x = 1;var y = 0;var z = 0;function ad ...
- luogu3629 [APIO2010]巡逻
创造一个环出来,可以让环上的边都只访问一次. 对于 \(k=1\),答案就是树的直径两边连起来. 倘若 \(k=2\),那就先按照 \(k=1\) 的求一遍,然后我们发现,如果第二条加的边构成的环和第 ...
- 设置Putty 字体 颜色 全屏
效果 1. 字体 2.全屏 3. 颜色 Window->Colours->Default Foreground->Modify设置(我喜欢绿色设置:R:0 G:255 B:0) ...
- IndiaHacks 2nd Elimination 2017 (unofficial, unrated mirror, ICPC rules)
D. Airplane Arrangements time limit per test 2 seconds memory limit per test 256 megabytes input sta ...
- 九度oj 题目1337:寻找最长合法括号序列
题目描述: 给你一个长度为N的,由’(‘和’)’组成的括号序列,你能找出这个序列中最长的合法括号子序列么?合法括号序列的含义便是,在这个序列中,所有的左括号都有唯一的右括号匹配:所有的右括号都有唯一的 ...
- 九度oj 题目1131:合唱队形
题目描述: N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1, 2, …, K,他们 ...
- BZOJ 2882 工艺 ——后缀自动机 最小表示法
先说后缀自动机的做法. 直接把S串复制一遍成SS,然后建立后缀自动机,go边相当于在当前字符的后面插入,而son边可以看作在字符串前面加一个字符. 所以贪心的走字典序最小的边即可,而且根据后缀自动机的 ...
- 在 Linux 实例上自动安装并运行 VNC Server
原文网址:https://help.aliyun.com/knowledge_detail/41181.html?spm=5176.8208715.110.11.4c184ae8mlC7Yy 您可以使 ...
- noj 2068 爱魔法的露露 [线性扫一遍]
njczy2010 2068 Accepted 325MS 8052K 1450Byte G++ 2014-11-13 11:20:40.0 爱魔法的露露 时间限制(普通/Java) : 1200 ...