package android.support.v4.util;
public class LruCache<K, V> {
private final LinkedHashMap<K, V> map;//数据结构
private int size;//已经存储的大小
private int maxSize;//规定的最大存储空间
private int putCount;//put的次数
private int createCount;//create的次数
private int evictionCount; //回收的次数
private int hitCount;//命中的次数
private int missCount; //丢失的次数
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
//第3个参数
//false: 基于插入顺序 true: 基于访问顺序(从最少到最多)
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
//重新设置最大存储空间
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);
//如果map中存在值,直接返回
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
//map中不存在,可重写create方法,根据key,创建一个值
V createdValue = create(key);
if (createdValue == null) {
return null;
}
synchronized (this) {
createCount++;
mapValue = map.put(key, createdValue);
//create方法可能会执行很长时间,导致create执行完后,map发生了改变,key对应的value已经存在,这时舍弃这一次put
if (mapValue != null) {
// There was a conflict so undo that last put
map.put(key, mapValue);
} else {
//更新当前存储的size大小
size += safeSizeOf(key, createdValue);
}
}
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++;
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {
//之前值被覆盖,要减去它的大小
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
//通知子类,值被覆盖
entryRemoved(false, key, previous, value);
}
//检测存储的大小是否超出
trimToSize(maxSize);
return previous;
}
//检测存储的大小是否超出
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 || map.isEmpty()) {
break;
}
//将最近访问最少的这个值删除,
//在android.util下的Lrucache实现代码如下:
//Map.Entry<K, V> toEvict = map.eldest();
//android.support.v4.util的实现如下:
Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
//如果当前size超过预设的最大值,则将最近访问最少的这个值删除,同时更新size大小
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
//有值要移除,子类可重写此方法来接收
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);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, null);
}
return previous;
}
//有值要移除,子类可重写此方法来接收,第一个参数true表示是因为存储满了而要回收的
protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
//当要取的值不存在时,子类可重写此方法创建一个
protected V create(K key) {
return null;
}
//确保每一个value的大小不能小于0
private int safeSizeOf(K key, V value) {
int result = sizeOf(key, value);
if (result < 0) {
throw new IllegalStateException("Negative size: " + key + "=" + value);
}
return result;
}
//子类要重写此方法返回每一个value的大小,如果缓存的是图片,则要返回每张图片的大小
protected int sizeOf(K key, V value) {
return 1;
}
//清空缓存
public final void evictAll() {
trimToSize(-1); // -1 will evict 0-sized elements
}
public synchronized final int size() {
return size;
}
public synchronized final int maxSize() {
return maxSize;
}
public synchronized final int hitCount() {
return hitCount;
}
public synchronized final int missCount() {
return missCount;
}
public synchronized final int createCount() {
return createCount;
}
public synchronized final int putCount() {
return putCount;
}
public synchronized final int evictionCount() {
return evictionCount;
}
//返回当前存储map的快照
public synchronized final Map<K, V> snapshot() {
return new LinkedHashMap<K, V>(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);
}
}
LruCache
最新推荐文章于 2023-10-13 16:56:20 发布