现在大多数的内存缓存都是用这个LRUCache来进行缓存的,算法主要就是 最近最少使用
但是其中的原理,有时候没有稍微深入研究的话,还是停留下会用的程度上(会用还不行了 :)(捂脸)
深入源码之前先简单的使用一下,图片缓存大致就是这样使用的
//获取应用程序的最大可用内存
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory / 8;
LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
//这里一定要复写 ,返回的是bitmap的大小
return bitmap.getByteCount();
}
};
Bitmap bitmap = createBitmap() ;
lruCache.put("url1", bitmap);
lruCache.put("url2", bitmap);
lruCache.put("url3", bitmap);
Bitmap bitmap1 = lruCache.get("url1")
上面就是正常的使用;然后就是查看源码中为什么是会是 最近最少使用的算法
- new 对象需要做的操作
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
//maxSize就是我们必须传入的大小限制,
this.maxSize = maxSize;
//注意这里就是使用LinkedHashMap来进行内存缓存的策略
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}put
- put的操作,map的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++;
//这里的safeSizeOf 最后会调用sizeOf方法,如果我们复写这个方法就使用,没有复写就返回 1
size += safeSizeOf(key, value);
//这里调用map的put方法,如果previous存在,将这个替换的previous 减去它的大小;
previous = map.put(key, value);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
//如果复写这个方法,就会调用,一般不用关心
if (previous != null) {
entryRemoved(false, key, previous, value);
}
//记住下面的方法,就是删除的操作!!!下面会重点介绍
trimToSize(maxSize);
return previous;
}
- get操作 , map的get方法
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++;
return mapValue;
}
missCount++;
}
}
- trimToSize操作,这是重点!!!
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;
}
//如果size > maxSize 就进行删除操作
//这里就是取出map集合的第一个,进行remove,然后再次调用SizeOf更新size。
Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
其实LRUCache源码里看的差不多是对LinkedHashMap的封装!主要还是要去查询LinkedHashMap的源码才能知道为什么trimToSize中的方法里map取迭代器的第一个就是删除最近少使用的那个item了。
- 对于LinkedHashMap的源码分析,大家可以参照下这个大佬的说明,很是详细的!