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

在之前讲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 <= 0) {

throw new IllegalArgumentException("maxSize <= 0");

}

this.maxSize = maxSize;

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

this.map = new LinkedHashMap(0, 0.75f, true);

}

// 重新设置 cache 最大容量

public void resize(int maxSize) {

if (maxSize <= 0) {

throw new IllegalArgumentException("maxSize <= 0");

}

synchronized (this) {

this.maxSize = maxSize;

}

trimToSize(maxSize);

}

public final V get(K key) {

if (key == null) {

throw new NullPointerException("key == null");

}

V mapValue;

synchronized (this) {// 同步访问

mapValue = map.get(key);

if (mapValue != null) {

hitCount++;// 命中次数 + 1

return mapValue;

}

missCount++;// 未命中次数 + 1

}

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

if (createdValue == null) {// 创建失败

return null;

}

synchronized (this) {

createCount++;// 构建 value 成功次数 + 1

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

if (mapValue != null) {

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

map.put(key, mapValue);

} else {

size += safeSizeOf(key, createdValue);// cache 大小增加

}

}

if (mapValue != null) {

entryRemoved(false, key, createdValue, mapValue);

return mapValue;

} else {

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

return createdValue;

}

}

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++;// put 次数

size += safeSizeOf(key, value);

previous = map.put(key, value);

if (previous != null) {

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

}

}

if (previous != 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 != 0)) {

throw new IllegalStateException(getClass().getName()

+ ".sizeOf() is reporting inconsistent results!");

}

if (size <= maxSize) {

break;

}

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

if (toEvict == null) {// 没有可以删除的key:value了

break;

}

key = toEvict.getKey();

value = toEvict.getValue();

map.remove(key);

size -= safeSizeOf(key, value);// 大小降低

evictionCount++;// 驱逐次数 + 1

}

entryRemoved(true, key, value, null);

}

}

public final V remove(K key) {

if (key == null) {

throw new NullPointerException("key == null");

}

V previous;

synchronized (this) {

previous = map.remove(key);// 通过 LinkedHashMap 移除

if (previous != null) {

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

}

}

if (previous != 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 = sizeOf(key, value);

if (result < 0) {

throw new IllegalStateException("Negative size: " + key + "=" + 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);

}

@Override

public synchronized final String toString() {

int accesses = hitCount + missCount;

int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;

return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",

maxSize, hitCount, missCount, hitPercent);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值